From a8297e6a8ef8625e9af348558e7caf1b789ee689 Mon Sep 17 00:00:00 2001 From: tenplus1 Date: Sat, 10 Aug 2024 13:18:57 +0100 Subject: [PATCH] tidy and tweak code, implement sound check for mineclon* --- api.lua | 716 +++++++++++++++++++++++------------------------ crafts.lua | 172 +++++------- init.lua | 22 +- lucky_block.lua | 22 +- mod.conf | 2 +- mount.lua | 110 +++----- settingtypes.txt | 2 - spawner.lua | 67 ++--- 8 files changed, 492 insertions(+), 621 deletions(-) diff --git a/api.lua b/api.lua index e9a4a31..a4d5249 100644 --- a/api.lua +++ b/api.lua @@ -1,25 +1,25 @@ --- Translation support + +-- translation and mod checks + local S = minetest.get_translator("mobs") local FS = function(...) return minetest.formspec_escape(S(...)) end - --- CMI support check local use_cmi = minetest.global_exists("cmi") - --- MineClone2 check -local use_mc2 = minetest.get_modpath("mcl_core") - --- Visual Harm 1ndicator check +local use_mc2 = minetest.get_modpath("mcl_core") -- MineClonia support local use_vh1 = minetest.get_modpath("visual_harm_1ndicators") +local use_tr = minetest.get_modpath("toolranks") -- Node check helper + local function has(nodename) if nodename and minetest.registered_nodes[nodename] then return nodename end end --- Global +-- Global table + mobs = { mod = "redo", - version = "20240809", + version = "20240810", + spawning_mobs = {}, translate = S, invis = minetest.global_exists("invisibility") and invisibility or {}, node_snow = has(minetest.registered_aliases["mapgen_snow"]) @@ -30,6 +30,7 @@ mobs = { mobs.fallback_node = mobs.node_dirt -- localize common functions + local pi = math.pi local square = math.sqrt local sin = math.sin @@ -54,12 +55,14 @@ local vsubtract = vector.subtract local settings = minetest.settings -- creative check + local creative_cache = minetest.settings:get_bool("creative_mode") function mobs.is_creative(name) return creative_cache or minetest.check_player_privs(name, {creative = true}) end -- Load settings + local damage_enabled = settings:get_bool("enable_damage") local mobs_spawn = settings:get_bool("mobs_spawn") ~= false local peaceful_only = settings:get_bool("only_peaceful_mobs") @@ -82,14 +85,12 @@ local mob_height_fix = settings:get_bool("mob_height_fix") ~= false local mob_log_spawn = settings:get_bool("mob_log_spawn") == true local active_mobs = 0 --- get loop timers for node and main functions +-- loop interval for node and main functions timers local node_timer_interval = tonumber(settings:get("mob_node_timer_interval") or 0.25) local main_timer_interval = tonumber(settings:get("mob_main_timer_interval") or 1.0) -- pathfinding settings local pathfinding_enable = settings:get_bool("mob_pathfinding_enable") or true --- Use pathfinder mod if available -local pathfinder_enable = settings:get_bool("mob_pathfinder_enable") or true -- how long before stuck mobs start searching local pathfinding_stuck_timeout = tonumber( settings:get("mob_pathfinding_stuck_timeout")) or 3.0 @@ -129,6 +130,7 @@ local aoc_range = tonumber(settings:get("active_block_range")) * 16 local creatura = minetest.get_modpath("creatura") and settings:get_bool("mobs_attack_creatura") == true +-- default mob settings mobs.mob_class = { state = "stand", @@ -205,6 +207,7 @@ local mob_class = mobs.mob_class -- Compatibility local mob_class_meta = {__index = mob_class} -- return True if number of mobs is at limit + local function at_limit() if active_limit and active_limit > 0 @@ -213,17 +216,15 @@ local function at_limit() end end - -- play sound + function mob_class:mob_sound(sound) if not sound then return end - -- higher pitch for a child - local pitch = self.child and 1.5 or 1.0 + local pitch = self.child and 1.5 or 1.0 -- higher pitch for a child - -- a little random pitch to be different - pitch = pitch + random(-10, 10) * 0.005 + pitch = pitch + random(-10, 10) * 0.005 -- little random pitch difference minetest.sound_play(sound, { object = self.object, @@ -233,8 +234,8 @@ function mob_class:mob_sound(sound) }, true) end - -- attack player/mob + function mob_class:do_attack(player, force) if self.state == "attack" and not force then return end @@ -245,8 +246,8 @@ function mob_class:do_attack(player, force) if random(100) < 90 then self:mob_sound(self.sounds.war_cry) end end - -- calculate distance + local get_distance = function(a, b) if not a or not b then return 50 end -- nil check and default distance @@ -256,8 +257,8 @@ local get_distance = function(a, b) return square(x * x + y * y + z * z) end - -- are we a real player ? + local function is_player(player) if player and type(player) == "userdata" and minetest.is_player(player) then @@ -265,8 +266,8 @@ local function is_player(player) end end - -- collision function based on jordan4ibanez' open_ai mod + function mob_class:collision() local pos = self.object:get_pos() ; if not pos then return {0, 0} end @@ -294,8 +295,8 @@ function mob_class:collision() return({x, z}) end - -- check if string exists in another string or table + local function check_for(look_for, look_inside) if type(look_inside) == "string" and look_inside == look_for then return true @@ -316,8 +317,8 @@ local function check_for(look_for, look_inside) end end - -- move mob in facing direction + function mob_class:set_velocity(v) -- halt mob if it has been ordered to stay @@ -356,8 +357,8 @@ function mob_class:set_velocity(v) x = (sin(yaw) * -v) + c_x, y = vel.y, z = (cos(yaw) * v) + c_y}) end - -- calculate mob velocity + function mob_class:get_velocity() local v = self.object:get_velocity() ; if not v then return 0 end @@ -365,8 +366,8 @@ function mob_class:get_velocity() return (v.x * v.x + v.z * v.z) ^ 0.5 end - -- set and return valid yaw + function mob_class:set_yaw(yaw, delay) if not yaw or yaw ~= yaw then yaw = 0 end @@ -393,13 +394,12 @@ function mob_class:set_yaw(yaw, delay) return self.target_yaw end --- global function to set mob yaw [deprecated] -function mobs:yaw(entity, yaw, delay) +function mobs:yaw(entity, yaw, delay) -- [deprecated] mob_class.set_yaw(entity, yaw, delay) end - -- set defined animation + function mob_class:set_animation(anim, force) if not self.animation or not anim then return end @@ -444,13 +444,12 @@ function mob_class:set_animation(anim, force) 0, self.animation[anim .. "_loop"] ~= false) end --- global function to set mob animation [deprecated] -function mobs:set_animation(entity, anim) +function mobs:set_animation(entity, anim) -- [deprecated] entity.set_animation(entity, anim) end - -- check line of sight using raycasting (thanks Astrobe) + function mob_class:line_of_sight(pos1, pos2) local ray = minetest.raycast(pos1, pos2, true, false) -- ignore entities @@ -472,18 +471,16 @@ function mob_class:line_of_sight(pos1, pos2) return true end --- global function [deprecated] -function mobs:line_of_sight(entity, pos1, pos2) +function mobs:line_of_sight(entity, pos1, pos2) -- [deprecated] return entity:line_of_sight(pos1, pos2) end +-- if mob not flying in medium it's suppose to, try and find some to return to function mob_class:attempt_flight_correction(override) if self:flight_check() and override ~= true then return true end - -- We are not flying in what we are supposed to. - -- See if we can find intended flight medium and return to it local pos = self.object:get_pos() ; if not pos then return true end local flyable_nodes = minetest.find_nodes_in_area( {x = pos.x - 1, y = pos.y - 1, z = pos.z - 1}, @@ -508,8 +505,8 @@ function mob_class:attempt_flight_correction(override) return true end - -- are we flying in what we are suppose to? (taikedz) + function mob_class:flight_check() local def = minetest.registered_nodes[self.standing_in] @@ -528,8 +525,8 @@ function mob_class:flight_check() return false end - -- turn mob to face position + function mob_class:yaw_to_pos(target, rot) rot = rot or 0 @@ -545,13 +542,12 @@ function mob_class:yaw_to_pos(target, rot) return yaw end --- global [deprecated] -function mobs:yaw_to_pos(self, target, rot) +function mobs:yaw_to_pos(self, target, rot) -- [deprecated] return self:yaw_to_pos(target, rot) end - -- if stay near set then periodically check for nodes and turn towards them + function mob_class:do_stay_near() if not self.stay_near then return false end @@ -560,13 +556,9 @@ function mob_class:do_stay_near() local searchnodes = self.stay_near[1] local chance = self.stay_near[2] or 10 - if not pos or random(chance) > 1 then - return false - end + if not pos or random(chance) > 1 then return false end - if type(searchnodes) == "string" then - searchnodes = {self.stay_near[1]} - end + if type(searchnodes) == "string" then searchnodes = {self.stay_near[1]} end local r = self.view_range local nearby_nodes = minetest.find_nodes_in_area( @@ -584,8 +576,8 @@ function mob_class:do_stay_near() return true end - -- custom particle effects + local function effect( pos, amount, texture, min_size, max_size, radius, gravity, glow, fall) @@ -618,21 +610,20 @@ local function effect( }) end --- global function function mobs:effect( pos, amount, texture, min_size, max_size, radius, gravity, glow, fall) effect(pos, amount, texture, min_size, max_size, radius, gravity, glow, fall) end - -- Thanks Wuzzy for the editable settings + local HORNY_TIME = 30 local HORNY_AGAIN_TIME = 60 * 5 -- 5 minutes local CHILD_GROW_TIME = 60 * 20 -- 20 minutes - -- update nametag and infotext + function mob_class:update_tag(newname) local col @@ -704,8 +695,8 @@ function mob_class:update_tag(newname) end end - -- drop items + function mob_class:item_drop() -- no drops if disabled by setting or mob is child @@ -781,8 +772,8 @@ function mob_class:item_drop() self.drops = {} end - -- remove mob and descrease counter + local function remove_mob(self, decrease) self.object:remove() @@ -793,13 +784,12 @@ local function remove_mob(self, decrease) end end --- global function for removing mobs function mobs:remove(self, decrease) remove_mob(self, decrease) end - -- check if mob is dead or only hurt + function mob_class:check_for_death(cmi_cause) -- We dead already @@ -916,8 +906,8 @@ function mob_class:check_for_death(cmi_cause) return true end - -- get node but use fallback for nil or unknown + local function node_ok(pos, fallback) local node = minetest.get_node_or_nil(pos) @@ -931,8 +921,8 @@ function mobs:node_ok(pos, fallback) return node_ok(pos, fallback) end - -- Returns true if node can deal damage to self + function mobs:is_node_dangerous(mob_object, nodename) if mob_object.water_damage > 0 @@ -953,8 +943,8 @@ local function is_node_dangerous(mob_object, nodename) return mobs:is_node_dangerous(mob_object, nodename) end - -- is mob facing a cliff + function mob_class:is_at_cliff() if self.driver or self.fear_height == 0 then -- 0 for no falling protection! @@ -986,8 +976,8 @@ function mob_class:is_at_cliff() return (not def and def.walkable) end - -- check for nodes or groups inside mob + function mob_class:is_inside(itemtable) local cb = self.object:get_properties().collisionbox @@ -999,8 +989,8 @@ function mob_class:is_inside(itemtable) if nn and #nn > 0 then return true end end - -- environmental damage (water, lava, fire, light etc.) + function mob_class:do_env_damage() local pos = self.object:get_pos() ; if not pos then return end @@ -1124,8 +1114,8 @@ function mob_class:do_env_damage() return self:check_for_death({type = "unknown"}) end +-- jump if facing a solid node that isn't a fences or gate --- jump if facing a solid node (not fences or gates) function mob_class:do_jump() local vel = self.object:get_velocity() ; if not vel then return false end @@ -1200,8 +1190,8 @@ function mob_class:do_jump() return false end - -- blast damage to entities nearby (modified from TNT mod) + local function entity_physics(pos, radius) radius = radius * 2 @@ -1223,15 +1213,15 @@ local function entity_physics(pos, radius) end end - -- can mob see player + local function is_invisible(self, player_name) if mobs.invis[player_name] and not self.ignore_invisibility then return true end end - -- should mob follow what I'm holding ? + function mob_class:follow_holding(clicker) if is_invisible(self, clicker:get_player_name()) then return false end @@ -1242,8 +1232,8 @@ function mob_class:follow_holding(clicker) if check_for(item:get_name(), self.follow) then return true end end - -- find two animals of same type and breed if nearby and horny + function mob_class:breed() -- child takes a long time before growing into adult @@ -1407,17 +1397,14 @@ function mob_class:breed() end end - -- find and replace what mob is looking for (grass, wheat etc.) + function mob_class:replace(pos) local vel = self.object:get_velocity() ; if not vel then return end - if not mobs_griefing - or not self.replace_rate or not self.replace_what - or self.child == true - or vel.y ~= 0 - or random(self.replace_rate) > 1 then + if not mobs_griefing or not self.replace_rate or not self.replace_what + or self.child == true or vel.y ~= 0 or random(self.replace_rate) > 1 then return end @@ -1459,19 +1446,16 @@ function mob_class:replace(pos) end end - -- check if daytime and also if mob is docile during daylight hours + function mob_class:day_docile() if self.docile_by_day == true and self.time_of_day > 0.2 and self.time_of_day < 0.8 then return true end end - -local los_switcher = false -local height_switcher = false - -- are we able to dig this node and add drops? + local function can_dig_drop(pos) if minetest.is_protected(pos, "") then return false end @@ -1500,11 +1484,14 @@ local function can_dig_drop(pos) end end +-- pathfinder mod check and settings local pathfinder_mod = minetest.get_modpath("pathfinder") +local los_switcher = false +local height_switcher = false + +-- path finding and smart mob routine by rnd, line_of_sight and other edits by Elkien3 --- path finding and smart mob routine by rnd, --- line_of_sight and other edits by Elkien3 function mob_class:smart_mobs(s, p, dist, dtime) local s1 = self.path.lastpos @@ -1626,7 +1613,7 @@ function mob_class:smart_mobs(s, p, dist, dtime) elseif prop.stepheight > 0.5 then jumpheight = 1 end - if pathfinder_mod and pathfinder_enable then + if pathfinder_mod then self.path.way = pathfinder.find_path(s, p1, self, dtime) else self.path.way = minetest.find_path(s, p1, pathfinding_searchdistance, @@ -1734,8 +1721,8 @@ function mob_class:smart_mobs(s, p, dist, dtime) end end +-- temporary entity for go_to() function --- temp entity for go_to() function minetest.register_entity("mobs:_pos", { initial_properties = { visual = "sprite", texture = "", hp_max = 1, physical = false, @@ -1751,6 +1738,7 @@ minetest.register_entity("mobs:_pos", { }) -- add temp entity and make mob go to that entity position + function mob_class:go_to(pos) local obj = minetest.add_entity(pos, "mobs:_pos") @@ -1758,8 +1746,8 @@ function mob_class:go_to(pos) if obj and obj:get_luaentity() then self:do_attack(obj, true) end end - -- peaceful player privilege support + local function is_peaceful_player(player) -- main setting enabled @@ -1773,8 +1761,8 @@ local function is_peaceful_player(player) end end - -- general attack function for all mobs + function mob_class:general_attack() -- return if already attacking, passive or docile during day @@ -1868,8 +1856,8 @@ function mob_class:general_attack() end end - -- find someone to runaway from + function mob_class:do_runaway_from() if not self.runaway_from then return end @@ -1947,8 +1935,8 @@ function mob_class:do_runaway_from() end end - -- follow player if owner or holding item, if fish outta water then flop + function mob_class:follow_flop() -- find player to follow @@ -2042,8 +2030,8 @@ function mob_class:follow_flop() end end - -- dogshoot attack switch and counter function + function mob_class:dogswitch(dtime) -- switch mode not activated @@ -2066,8 +2054,8 @@ function mob_class:dogswitch(dtime) return self.dogshoot_switch end +-- stop attack and reset vars --- stop attack function mob_class:stop_attack() self.attack = nil @@ -2081,8 +2069,8 @@ function mob_class:stop_attack() self:set_animation("stand", true) end - -- execute current state (stand, walk, run, attacks) + function mob_class:do_states(dtime) local yaw = self.object:get_yaw() ; if not yaw then return end @@ -2565,8 +2553,8 @@ function mob_class:do_states(dtime) end end - -- falling and fall damage + function mob_class:falling(pos) if self.fly or self.disable_falling then return end @@ -2609,11 +2597,8 @@ function mob_class:falling(pos) self.object:set_acceleration({x = 0, y = fall_speed, z = 0}) end - --- is Took Ranks mod active? -local tr = minetest.get_modpath("toolranks") - -- deal damage and effects when mob punched + function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) -- mob health check @@ -2746,10 +2731,10 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) end if mobs.is_creative(hitter:get_player_name()) then - wear = tr and 1 or 0 + wear = use_tr and 1 or 0 end - if tr and weapon_def.original_description then + if use_tr and weapon_def.original_description then toolranks.new_afteruse(weapon, hitter, nil, {wear = wear}) else weapon:add_wear(wear) @@ -2924,8 +2909,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage) return true end - -- helper function to clean mob staticdata + local function clean_staticdata(self) local tmp, t = {} @@ -2943,8 +2928,8 @@ local function clean_staticdata(self) return tmp end - -- get entity staticdata + function mob_class:mob_staticdata() -- this handles mob count for mobs activated, unloaded, reloaded @@ -3003,6 +2988,7 @@ function mob_class:mob_staticdata() return minetest.serialize(clean_staticdata(self)) end +-- list of items used in initial_properties local is_property_name = { hp_max = true, physical = true, collide_with_objects = true, collisionbox = true, @@ -3011,6 +2997,7 @@ local is_property_name = { } -- activate mob and reload settings + function mob_class:mob_activate(staticdata, def, dtime) -- if dtime == 0 then entity has just been created @@ -3161,8 +3148,8 @@ function mob_class:mob_activate(staticdata, def, dtime) end end - -- handle mob lifetimer and expiration + function mob_class:mob_expire(pos, dtime) -- when lifetimer expires remove mob (except npc and tamed) @@ -3193,8 +3180,8 @@ function mob_class:mob_expire(pos, dtime) end end +-- get nodes mob is standing on, in, facing, facing above --- get nodes mob is standing on/in, facing/above function mob_class:get_nodes() local pos = self.object:get_pos() @@ -3237,8 +3224,8 @@ print("on: " .. self.standing_on ]] end - -- main mob function + function mob_class:on_step(dtime, moveresult) if self.state == "die" then return end @@ -3379,8 +3366,8 @@ function mob_class:on_step(dtime, moveresult) end end - -- default function when mobs are blown up with TNT + function mob_class:on_blast(damage) --print("-- blast damage", damage) @@ -3392,10 +3379,8 @@ function mob_class:on_blast(damage) return false, false, {} end - -mobs.spawning_mobs = {} - -- register mob entity + function mobs:register_mob(name, def) mobs.spawning_mobs[name] = {} @@ -3407,152 +3392,151 @@ function mobs:register_mob(name, def) collisionbox[5] = collisionbox[2] + 0.99 end -minetest.register_entity(":" .. name, setmetatable({ + minetest.register_entity(":" .. name, setmetatable({ - initial_properties = { - hp_max = max(1, (def.hp_max or 10) * difficulty), - physical = true, - collisionbox = collisionbox, - selectionbox = def.selectionbox or collisionbox, - visual = def.visual, - visual_size = def.visual_size or {x = 1, y = 1}, - mesh = def.mesh, - textures = "", - makes_footstep_sound = def.makes_footstep_sound, - stepheight = def.stepheight or 1.1, - glow = def.glow, - damage_texture_modifier = def.damage_texture_modifier or "^[colorize:#c9900070", - }, + initial_properties = { + hp_max = max(1, (def.hp_max or 10) * difficulty), + physical = true, + collisionbox = collisionbox, + selectionbox = def.selectionbox or collisionbox, + visual = def.visual, + visual_size = def.visual_size or {x = 1, y = 1}, + mesh = def.mesh, + textures = "", + makes_footstep_sound = def.makes_footstep_sound, + stepheight = def.stepheight or 1.1, + glow = def.glow, + damage_texture_modifier = def.damage_texture_modifier or "^[colorize:#c9900070", + }, - name = name, - type = def.type, - _nametag = def.nametag, - attack_type = def.attack_type, - fly = def.fly, - fly_in = def.fly_in, - keep_flying = def.keep_flying, - owner = def.owner, - order = def.order, - jump_height = def.jump_height, - can_leap = def.can_leap, - drawtype = def.drawtype, -- DEPRECATED, use rotate instead - rotate = rad(def.rotate or 0), -- 0=front 90=side 180=back 270=side2 - lifetimer = def.lifetimer, - hp_min = max(1, (def.hp_min or 5) * difficulty), + name = name, + type = def.type, + _nametag = def.nametag, + attack_type = def.attack_type, + fly = def.fly, + fly_in = def.fly_in, + keep_flying = def.keep_flying, + owner = def.owner, + order = def.order, + jump_height = def.jump_height, + can_leap = def.can_leap, + drawtype = def.drawtype, -- DEPRECATED, use rotate instead + rotate = rad(def.rotate or 0), -- 0=front 90=side 180=back 270=side2 + lifetimer = def.lifetimer, + hp_min = max(1, (def.hp_min or 5) * difficulty), - -- backup entity model and size - base_mesh = def.mesh, - base_colbox = collisionbox, - base_selbox = def.selectionbox or collisionbox, - base_size = def.visual_size or {x = 1, y = 1}, + -- backup entity model and size + base_mesh = def.mesh, + base_colbox = collisionbox, + base_selbox = def.selectionbox or collisionbox, + base_size = def.visual_size or {x = 1, y = 1}, - view_range = def.view_range, - walk_velocity = def.walk_velocity, - run_velocity = def.run_velocity, - damage = max(0, (def.damage or 0) * difficulty), - damage_group = def.damage_group, - light_damage = def.light_damage, - light_damage_min = def.light_damage_min, - light_damage_max = def.light_damage_max, - water_damage = def.water_damage, - lava_damage = def.lava_damage, - fire_damage = def.fire_damage, - air_damage = def.air_damage, - node_damage = def.node_damage, - suffocation = def.suffocation, - fall_damage = def.fall_damage, - fall_speed = def.fall_speed, - drops = def.drops, - armor = def.armor, - arrow = def.arrow, - arrow_override = def.arrow_override, - shoot_interval = def.shoot_interval, - homing = def.homing, - sounds = def.sounds, - animation = def.animation, - follow = def.follow, - jump = def.jump, - walk_chance = def.walk_chance, - stand_chance = def.stand_chance, - attack_chance = def.attack_chance, - attack_patience = def.attack_patience, - passive = def.passive, - knock_back = def.knock_back, - blood_amount = def.blood_amount, - blood_texture = def.blood_texture, - shoot_offset = def.shoot_offset, - floats = def.floats, - replace_rate = def.replace_rate, - replace_what = def.replace_what, - replace_with = def.replace_with, - replace_offset = def.replace_offset, - reach = def.reach, - texture_list = def.textures, - texture_mods = def.texture_mods or "", - child_texture = def.child_texture, - docile_by_day = def.docile_by_day, - fear_height = def.fear_height, - runaway = def.runaway, - pathfinding = def.pathfinding, - immune_to = def.immune_to, - explosion_radius = def.explosion_radius, - explosion_damage_radius = def.explosion_damage_radius, - explosion_timer = def.explosion_timer, - allow_fuse_reset = def.allow_fuse_reset, - stop_to_explode = def.stop_to_explode, - double_melee_attack = def.double_melee_attack, - dogshoot_switch = def.dogshoot_switch, - dogshoot_count_max = def.dogshoot_count_max, - dogshoot_count2_max = def.dogshoot_count2_max or def.dogshoot_count_max, - group_attack = def.group_attack, - group_helper = def.group_helper, - attack_monsters = def.attacks_monsters or def.attack_monsters, - attack_animals = def.attack_animals, - attack_players = def.attack_players, - attack_npcs = def.attack_npcs, - attack_ignore = def.attack_ignore, - specific_attack = def.specific_attack, - friendly_fire = def.friendly_fire, - runaway_from = def.runaway_from, - owner_loyal = def.owner_loyal, - pushable = def.pushable, - stay_near = def.stay_near, - randomly_turn = def.randomly_turn ~= false, - ignore_invisibility = def.ignore_invisibility, - messages = def.messages, + view_range = def.view_range, + walk_velocity = def.walk_velocity, + run_velocity = def.run_velocity, + damage = max(0, (def.damage or 0) * difficulty), + damage_group = def.damage_group, + light_damage = def.light_damage, + light_damage_min = def.light_damage_min, + light_damage_max = def.light_damage_max, + water_damage = def.water_damage, + lava_damage = def.lava_damage, + fire_damage = def.fire_damage, + air_damage = def.air_damage, + node_damage = def.node_damage, + suffocation = def.suffocation, + fall_damage = def.fall_damage, + fall_speed = def.fall_speed, + drops = def.drops, + armor = def.armor, + arrow = def.arrow, + arrow_override = def.arrow_override, + shoot_interval = def.shoot_interval, + homing = def.homing, + sounds = def.sounds, + animation = def.animation, + follow = def.follow, + jump = def.jump, + walk_chance = def.walk_chance, + stand_chance = def.stand_chance, + attack_chance = def.attack_chance, + attack_patience = def.attack_patience, + passive = def.passive, + knock_back = def.knock_back, + blood_amount = def.blood_amount, + blood_texture = def.blood_texture, + shoot_offset = def.shoot_offset, + floats = def.floats, + replace_rate = def.replace_rate, + replace_what = def.replace_what, + replace_with = def.replace_with, + replace_offset = def.replace_offset, + reach = def.reach, + texture_list = def.textures, + texture_mods = def.texture_mods or "", + child_texture = def.child_texture, + docile_by_day = def.docile_by_day, + fear_height = def.fear_height, + runaway = def.runaway, + pathfinding = def.pathfinding, + immune_to = def.immune_to, + explosion_radius = def.explosion_radius, + explosion_damage_radius = def.explosion_damage_radius, + explosion_timer = def.explosion_timer, + allow_fuse_reset = def.allow_fuse_reset, + stop_to_explode = def.stop_to_explode, + double_melee_attack = def.double_melee_attack, + dogshoot_switch = def.dogshoot_switch, + dogshoot_count_max = def.dogshoot_count_max, + dogshoot_count2_max = def.dogshoot_count2_max or def.dogshoot_count_max, + group_attack = def.group_attack, + group_helper = def.group_helper, + attack_monsters = def.attacks_monsters or def.attack_monsters, + attack_animals = def.attack_animals, + attack_players = def.attack_players, + attack_npcs = def.attack_npcs, + attack_ignore = def.attack_ignore, + specific_attack = def.specific_attack, + friendly_fire = def.friendly_fire, + runaway_from = def.runaway_from, + owner_loyal = def.owner_loyal, + pushable = def.pushable, + stay_near = def.stay_near, + randomly_turn = def.randomly_turn ~= false, + ignore_invisibility = def.ignore_invisibility, + messages = def.messages, - on_rightclick = def.on_rightclick, - on_die = def.on_die, - on_death = def.on_death, -- engine function for entity death - on_flop = def.on_flop, - do_custom = def.do_custom, - on_replace = def.on_replace, - custom_attack = def.custom_attack, + on_rightclick = def.on_rightclick, + on_die = def.on_die, + on_death = def.on_death, -- engine function for entity death + on_flop = def.on_flop, + do_custom = def.do_custom, + on_replace = def.on_replace, + custom_attack = def.custom_attack, - on_spawn = def.on_spawn, - on_blast = def.on_blast, -- class redifinition - do_punch = def.do_punch, - on_breed = def.on_breed, - on_grown = def.on_grown, - on_sound = def.on_sound, + on_spawn = def.on_spawn, + on_blast = def.on_blast, -- class redifinition + do_punch = def.do_punch, + on_breed = def.on_breed, + on_grown = def.on_grown, + on_sound = def.on_sound, - is_mob = true, _hittable_by_projectile = true, -- mineclone thing + is_mob = true, _hittable_by_projectile = true, -- mineclone thing - on_activate = function(self, staticdata, dtime) - return self:mob_activate(staticdata, def, dtime) - end, + on_activate = function(self, staticdata, dtime) + return self:mob_activate(staticdata, def, dtime) + end, - get_staticdata = function(self) - return self:mob_staticdata(self) - end - -}, mob_class_meta)) - -end -- END mobs:register_mob function + get_staticdata = function(self) + return self:mob_staticdata(self) + end + }, mob_class_meta)) +end -- count how many mobs of one type are inside an area -- will also return true for second value if player is inside area + local function count_mobs(pos, type) local total = 0 @@ -3575,8 +3559,8 @@ local function count_mobs(pos, type) return total, players end - -- do we have enough space to spawn mob? (thanks wuzzy) + local function can_spawn(pos, name) local ent = minetest.registered_entities[name] @@ -3630,7 +3614,6 @@ function mobs:can_spawn(pos, name) return can_spawn(pos, name) end - -- global functions function mobs:add_mob(pos, def) @@ -3698,24 +3681,17 @@ function mobs:add_mob(pos, def) mob:set_properties({ textures = new_texture, visual_size = { - x = ent.base_size.x * .5, - y = ent.base_size.y * .5 + x = ent.base_size.x * .5, y = ent.base_size.y * .5 }, collisionbox = { - ent.base_colbox[1] * .5, - ent.base_colbox[2] * .5, - ent.base_colbox[3] * .5, - ent.base_colbox[4] * .5, - ent.base_colbox[5] * .5, - ent.base_colbox[6] * .5 + ent.base_colbox[1] * .5, ent.base_colbox[2] * .5, + ent.base_colbox[3] * .5, ent.base_colbox[4] * .5, + ent.base_colbox[5] * .5, ent.base_colbox[6] * .5 }, selectionbox = { - ent.base_selbox[1] * .5, - ent.base_selbox[2] * .5, - ent.base_selbox[3] * .5, - ent.base_selbox[4] * .5, - ent.base_selbox[5] * .5, - ent.base_selbox[6] * .5 + ent.base_selbox[1] * .5, ent.base_selbox[2] * .5, + ent.base_selbox[3] * .5, ent.base_selbox[4] * .5, + ent.base_selbox[5] * .5, ent.base_selbox[6] * .5 } }) @@ -3747,12 +3723,13 @@ function mobs:add_mob(pos, def) return ent end +-- global function to add additional spawn checks function mobs:spawn_abm_check(pos, node, name) - -- global function to add additional spawn checks -- return true to stop spawning mob end +-- older spawning function function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval, chance, aoc, min_height, max_height, day_toggle, on_spawn, map_load) @@ -3936,7 +3913,6 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter end end - -- are we registering an abm or lbm? if map_load == true then @@ -3966,8 +3942,8 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter end end - -- compatibility with older mob registration [DEPRECATED] + function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle) @@ -3975,8 +3951,8 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, chance, active_object_count, -31000, max_height, day_toggle) end +-- MarkBu's newer spawn function (USE this one please modders) --- MarkBu's spawn function (USE this one please) function mobs:spawn(def) mobs:spawn_specific( @@ -3995,8 +3971,8 @@ function mobs:spawn(def) def.on_map_load) end - -- register arrow for shoot attack + function mobs:register_arrow(name, def) if not name or not def then return end @@ -4163,14 +4139,8 @@ function mobs:register_arrow(name, def) }) end - --- compatibility function (deprecated) -function mobs:explosion(pos, radius) - mobs:boom({sounds = {explode = "tnt_explode"}}, pos, radius, radius, "tnt_smoke.png") -end - - -- no damage to nodes explosion + function mobs:safe_boom(self, pos, radius, texture) minetest.sound_play(self.sounds and self.sounds.explode or "tnt_explode", { @@ -4184,8 +4154,8 @@ function mobs:safe_boom(self, pos, radius, texture) effect(pos, 32, texture, radius * 3, radius * 5, radius, 1, 0) end - -- make explosion with protection and tnt mod check + function mobs:boom(self, pos, radius, damage_radius, texture) if mobs_griefing and minetest.get_modpath("tnt") and tnt and tnt.boom @@ -4203,11 +4173,14 @@ function mobs:boom(self, pos, radius, damage_radius, texture) end end +function mobs:explosion(pos, radius) -- [deprecated] compatibility function + mobs:boom({sounds = {explode = "tnt_explode"}}, pos, radius, radius, "tnt_smoke.png") +end + +-- Register spawn eggs - This also introduces the “spawn_egg” group: +-- * spawn_egg=1: generic mob, no metadata +-- * spawn_egg=2: captured/tamed mob, metadata --- Register spawn eggs --- Note: This also introduces the “spawn_egg” group: --- * spawn_egg=1: Spawn egg (generic mob, no metadata) --- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata) function mobs:register_egg(mob, desc, background, addegg, no_creative) local grp = {spawn_egg = 1} @@ -4230,64 +4203,64 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) end -- register new spawn egg containing mob information (cannot be stacked) - -- these are only created for animals and npc mobs, not monsters -if is_mob.type ~= "monster" then + -- these are only created for animals and npc's, not monsters + if is_mob.type ~= "monster" then - minetest.register_craftitem(":" .. mob .. "_set", { + minetest.register_craftitem(":" .. mob .. "_set", { - description = S("@1 (Tamed)", desc), - inventory_image = invimg, - groups = {spawn_egg = 2, not_in_creative_inventory = 1}, - stack_max = 1, + description = S("@1 (Tamed)", desc), + inventory_image = invimg, + groups = {spawn_egg = 2, not_in_creative_inventory = 1}, + stack_max = 1, - on_place = function(itemstack, placer, pointed_thing) + on_place = function(itemstack, placer, pointed_thing) - local pos = pointed_thing.above + local pos = pointed_thing.above - -- does existing on_rightclick function exist? - local under = minetest.get_node(pointed_thing.under) - local def = minetest.registered_nodes[under.name] + -- does existing on_rightclick function exist? + local under = minetest.get_node(pointed_thing.under) + local def = minetest.registered_nodes[under.name] - if def and def.on_rightclick then + if def and def.on_rightclick then - return def.on_rightclick( - pointed_thing.under, under, placer, itemstack, pointed_thing) - end - - if pos and not minetest.is_protected(pos, placer:get_player_name()) then - - -- have we reached active mob limit - if at_limit() then - - minetest.chat_send_player(placer:get_player_name(), - S("Active Mob Limit Reached!") - .. " (" .. active_mobs - .. " / " .. active_limit .. ")") - return + return def.on_rightclick( + pointed_thing.under, under, placer, itemstack, pointed_thing) end - pos.y = pos.y + 1 + if pos and not minetest.is_protected(pos, placer:get_player_name()) then - local data = itemstack:get_metadata() - local smob = minetest.add_entity(pos, mob, data) - local ent = smob and smob:get_luaentity() + -- have we reached active mob limit + if at_limit() then - if not ent then return end -- sanity check + minetest.chat_send_player(placer:get_player_name(), + S("Active Mob Limit Reached!") + .. " (" .. active_mobs + .. " / " .. active_limit .. ")") + return + end - -- set owner if not a monster - if ent.type ~= "monster" then - ent.owner = placer:get_player_name() - ent.tamed = true + pos.y = pos.y + 1 + + local data = itemstack:get_metadata() + local smob = minetest.add_entity(pos, mob, data) + local ent = smob and smob:get_luaentity() + + if not ent then return end -- sanity check + + -- set owner if not a monster + if ent.type ~= "monster" then + ent.owner = placer:get_player_name() + ent.tamed = true + end + + -- since mob is unique we remove egg once spawned + itemstack:take_item() end - -- since mob is unique we remove egg once spawned - itemstack:take_item() + return itemstack end - - return itemstack - end - }) -end + }) + end -- register old stackable mob egg minetest.register_craftitem(":" .. mob, { @@ -4346,8 +4319,8 @@ end }) end - -- force capture a mob if space available in inventory, or drop as spawn egg + function mobs:force_capture(self, clicker) -- add special mob egg with all mob information @@ -4370,8 +4343,8 @@ function mobs:force_capture(self, clicker) remove_mob(self, true) end - -- capture critter (thanks to blert2112 for idea) + function mobs:capture_mob( self, clicker, chance_hand, chance_net, chance_lasso, force_take, replacewith) @@ -4383,9 +4356,7 @@ function mobs:capture_mob( local mobname = self.name -- if not nil change what will be added to inventory - if replacewith then - mobname = replacewith - end + if replacewith then mobname = replacewith end local name = clicker:get_player_name() local tool = clicker:get_wielded_item() @@ -4486,8 +4457,8 @@ function mobs:capture_mob( return true end - -- protect tamed mob with rune item + function mobs:protect(self, clicker) local name = clicker:get_player_name() @@ -4533,11 +4504,10 @@ function mobs:protect(self, clicker) return true end +-- feeding, taming, breeding and naming (thanks blert2112) -local mob_obj = {} -local mob_sta = {} +local mob_obj, mob_sta = {}, {} --- feeding, taming and breeding (thanks blert2112) function mobs:feed_tame(self, clicker, feed_count, breed, tame) -- can eat/tame with item in hand @@ -4649,8 +4619,8 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame) return false end - -- inspired by blockmen's nametag mod + minetest.register_on_player_receive_fields(function(player, formname, fields) -- right-clicked with nametag and name entered? @@ -4685,8 +4655,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) - -- compatibility function for old mobs entities to new mobs_redo modpack + function mobs:alias_mob(old_name, new_name) -- check old_name entity doesnt already exist @@ -4718,8 +4688,8 @@ function mobs:alias_mob(old_name, new_name) }) end - -- admin command to remove untamed mobs around players + minetest.register_chatcommand("clear_mobs", { params = "", description = "Remove untamed mobs from around players.", @@ -4758,76 +4728,76 @@ minetest.register_chatcommand("clear_mobs", { end }) - -- Is mob hearing enabled, if so override minetest.sound_play with custom function + if settings:get_bool("mobs_can_hear") ~= false then -local old_sound_play = minetest.sound_play + local old_sound_play = minetest.sound_play -minetest.sound_play = function(spec, param, eph) + minetest.sound_play = function(spec, param, eph) - local def = {} ; param = param or {} + local def = {} ; param = param or {} - -- store sound position - if param.pos then - def.pos = param.pos - elseif param.object then - def.pos = param.object:get_pos() - elseif param.to_player then - def.pos = minetest.get_player_by_name(param.to_player):get_pos() - end + -- store sound position + if param.pos then + def.pos = param.pos + elseif param.object then + def.pos = param.object:get_pos() + elseif param.to_player then + def.pos = minetest.get_player_by_name(param.to_player):get_pos() + end - -- if no position found use default function - if not def.pos then - return old_sound_play(spec, param, eph) - end + -- if no position found use default function + if not def.pos then + return old_sound_play(spec, param, eph) + end - -- store sound name and gain - if type(spec) == "string" then - def.sound = spec - def.gain = param.gain or 1.0 - elseif type(spec) == "table" then - def.sound = spec.name - def.gain = spec.gain or param.gain or 1.0 - end + -- store sound name and gain + if type(spec) == "string" then + def.sound = spec + def.gain = param.gain or 1.0 + elseif type(spec) == "table" then + def.sound = spec.name + def.gain = spec.gain or param.gain or 1.0 + end - -- store player name or object reference - if param.to_player then - def.player = param.to_player - elseif param.object then - def.object = param.object - end + -- store player name or object reference + if param.to_player then + def.player = param.to_player + elseif param.object then + def.object = param.object + end - def.max_hear_distance = param.max_hear_distance or 32 + def.max_hear_distance = param.max_hear_distance or 32 - -- find mobs within sounds hearing range - local objs = minetest.get_objects_inside_radius(def.pos, def.max_hear_distance) + -- find mobs within sounds hearing range + local objs = minetest.get_objects_inside_radius(def.pos, def.max_hear_distance) - for n = 1, #objs do + for n = 1, #objs do - local obj = objs[n] + local obj = objs[n] - if not obj:is_player() then + if not obj:is_player() then - local ent = obj:get_luaentity() + local ent = obj:get_luaentity() - if ent and ent._cmi_is_mob and ent.on_sound then + if ent and ent._cmi_is_mob and ent.on_sound then - -- calculate loudness of sound to mob - def.distance = get_distance(def.pos, obj:get_pos()) + -- calculate loudness of sound to mob + def.distance = get_distance(def.pos, obj:get_pos()) - local bit = def.gain / def.max_hear_distance - local rem = def.max_hear_distance - def.distance + local bit = def.gain / def.max_hear_distance + local rem = def.max_hear_distance - def.distance - -- loudness ranges from 0 (cannot hear) to 1.0 (close to source) - def.loudness = (bit * rem) / def.gain + -- loudness ranges from 0 (cannot hear) to 1.0 (close to source) + def.loudness = (bit * rem) / def.gain - -- run custom on_sound function - ent.on_sound(ent, def) + -- run custom on_sound function + ent.on_sound(ent, def) + end end end - end - return old_sound_play(spec, param, eph) + return old_sound_play(spec, param, eph) + end end -end -- setting END diff --git a/crafts.lua b/crafts.lua index 44c49cb..539c52d 100644 --- a/crafts.lua +++ b/crafts.lua @@ -1,9 +1,31 @@ -local S = mobs.translate +local S = minetest.get_translator("mobs") local FS = function(...) return minetest.formspec_escape(S(...)) end local mc2 = minetest.get_modpath("mcl_core") +local mod_def = minetest.get_modpath("default") + +-- determine which sounds to use, default or mcl_sounds + +local function sound_helper(snd) + + mobs[snd] = (mod_def and default[snd]) or (mc2 and mcl_sounds[snd]) + or function() return {} end +end + +sound_helper("node_sound_defaults") +sound_helper("node_sound_stone_defaults") +sound_helper("node_sound_dirt_defaults") +sound_helper("node_sound_sand_defaults") +sound_helper("node_sound_gravel_defaults") +sound_helper("node_sound_wood_defaults") +sound_helper("node_sound_leaves_defaults") +sound_helper("node_sound_ice_defaults") +sound_helper("node_sound_metal_defaults") +sound_helper("node_sound_water_defaults") +sound_helper("node_sound_snow_defaults") -- helper function to add {eatable} group to food items + function mobs.add_eatable(item, hp) local def = minetest.registered_items[item] @@ -19,6 +41,7 @@ function mobs.add_eatable(item, hp) end -- recipe items + local items = { paper = mc2 and "mcl_core:paper" or "default:paper", dye_black = mc2 and "mcl_dye:black" or "dye:black", @@ -36,8 +59,8 @@ local items = { meat_cooked = mc2 and "mcl_mobitems:cooked_beef" or "group:food_meat", } - -- name tag + minetest.register_craftitem("mobs:nametag", { description = S("Name Tag") .. " " .. S("\nRight-click Mobs Redo mob to apply"), inventory_image = "mobs_nametag.png", @@ -52,6 +75,7 @@ minetest.register_craft({ }) -- leather + minetest.register_craftitem("mobs:leather", { description = S("Leather"), inventory_image = "mobs_leather.png", @@ -59,6 +83,7 @@ minetest.register_craftitem("mobs:leather", { }) -- raw meat + minetest.register_craftitem("mobs:meat_raw", { description = S("Raw Meat"), inventory_image = "mobs_meat_raw.png", @@ -69,6 +94,7 @@ minetest.register_craftitem("mobs:meat_raw", { mobs.add_eatable("mobs:meat_raw", 3) -- cooked meat + minetest.register_craftitem("mobs:meat", { description = S("Meat"), inventory_image = "mobs_meat.png", @@ -86,6 +112,7 @@ minetest.register_craft({ }) -- lasso + minetest.register_tool("mobs:lasso", { description = S("Lasso (right-click animal to put in inventory)"), inventory_image = "mobs_magic_lasso.png", @@ -104,6 +131,7 @@ minetest.register_craft({ minetest.register_alias("mobs:magic_lasso", "mobs:lasso") -- net + minetest.register_tool("mobs:net", { description = S("Net (right-click animal to put in inventory)"), inventory_image = "mobs_net.png", @@ -120,6 +148,7 @@ minetest.register_craft({ }) -- shears (right click to shear animal) + minetest.register_tool("mobs:shears", { description = S("Steel Shears (right-click to shear)"), inventory_image = "mobs_shears.png", @@ -135,6 +164,7 @@ minetest.register_craft({ }) -- protection rune + minetest.register_craftitem("mobs:protector", { description = S("Mob Protection Rune"), inventory_image = "mobs_protector.png", @@ -150,7 +180,8 @@ minetest.register_craft({ } }) --- level 2 protection rune +-- protection rune (level 2) + minetest.register_craftitem("mobs:protector2", { description = S("Mob Protection Rune (Level 2)"), inventory_image = "mobs_protector2.png", @@ -167,6 +198,7 @@ minetest.register_craft({ }) -- saddle + minetest.register_craftitem("mobs:saddle", { description = S("Saddle"), inventory_image = "mobs_saddle.png", @@ -182,29 +214,25 @@ minetest.register_craft({ } }) - --- make sure we can register fences -local mod_def = minetest.get_modpath("default") +-- register mob fence if default found if mod_def and default.register_fence then --- mob fence (looks like normal fence but collision is 2 high) -default.register_fence("mobs:fence_wood", { - description = S("Mob Fence"), - texture = "default_wood.png", - material = "default:fence_wood", - groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}, - sounds = mod_def and default.node_sound_wood_defaults(), - collision_box = { - type = "fixed", - fixed = { - {-0.5, -0.5, -0.5, 0.5, 1.9, 0.5}, + -- mob fence (looks like normal fence but collision is 2 high) + default.register_fence("mobs:fence_wood", { + description = S("Mob Fence"), + texture = "default_wood.png", + material = "default:fence_wood", + groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2}, + sounds = mobs.node_sound_wood_defaults(), + collision_box = { + type = "fixed", fixed = {{-0.5, -0.5, -0.5, 0.5, 1.9, 0.5}} } - } -}) + }) end -- mob fence top (has enlarged collisionbox to stop mobs getting over) + minetest.register_node("mobs:fence_top", { description = S("Mob Fence Top"), drawtype = "nodebox", @@ -212,19 +240,10 @@ minetest.register_node("mobs:fence_top", { paramtype = "light", is_ground_content = false, groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2, axey = 1}, - sounds = mod_def and default.node_sound_wood_defaults(), - node_box = { - type = "fixed", - fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2} - }, - collision_box = { - type = "fixed", - fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4} - }, - selection_box = { - type = "fixed", - fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4} - } + sounds = mobs.node_sound_wood_defaults(), + node_box = {type = "fixed", fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2}}, + collision_box = {type = "fixed", fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}}, + selection_box = {type = "fixed", fixed = {-0.4, -1.5, -0.4, 0.4, 0, 0.4}} }) minetest.register_craft({ @@ -235,49 +254,15 @@ minetest.register_craft({ } }) - -- items that can be used as fuel -minetest.register_craft({ - type = "fuel", - recipe = "mobs:nametag", - burntime = 3 -}) -minetest.register_craft({ - type = "fuel", - recipe = "mobs:lasso", - burntime = 7 -}) - -minetest.register_craft({ - type = "fuel", - recipe = "mobs:net", - burntime = 8 -}) - -minetest.register_craft({ - type = "fuel", - recipe = "mobs:leather", - burntime = 4 -}) - -minetest.register_craft({ - type = "fuel", - recipe = "mobs:saddle", - burntime = 7 -}) - -minetest.register_craft({ - type = "fuel", - recipe = "mobs:fence_wood", - burntime = 7 -}) - -minetest.register_craft({ - type = "fuel", - recipe = "mobs:fence_top", - burntime = 2 -}) +minetest.register_craft({type = "fuel", recipe = "mobs:nametag", burntime = 3}) +minetest.register_craft({type = "fuel", recipe = "mobs:lasso", burntime = 7}) +minetest.register_craft({type = "fuel", recipe = "mobs:net", burntime = 8}) +minetest.register_craft({type = "fuel", recipe = "mobs:leather", burntime = 4}) +minetest.register_craft({type = "fuel", recipe = "mobs:saddle", burntime = 7}) +minetest.register_craft({type = "fuel", recipe = "mobs:fence_wood", burntime = 7}) +minetest.register_craft({type = "fuel", recipe = "mobs:fence_top", burntime = 2}) -- this tool spawns same mob and adds owner, protected, nametag info @@ -294,12 +279,9 @@ minetest.register_tool(":mobs:mob_reset_stick", { on_use = function(itemstack, user, pointed_thing) - if pointed_thing.type ~= "object" then - return - end + if pointed_thing.type ~= "object" then return end local obj = pointed_thing.ref - local control = user:get_player_control() local sneak = control and control.sneak @@ -339,9 +321,7 @@ minetest.register_tool(":mobs:mob_reset_stick", { -- get base texture local bt = tex_obj:get_luaentity().base_texture[1] - if type(bt) ~= "string" then - bt = "" - end + if type(bt) ~= "string" then bt = "" end local name = user:get_player_name() @@ -357,27 +337,18 @@ minetest.register_tool(":mobs:mob_reset_stick", { minetest.register_on_player_receive_fields(function(player, formname, fields) -- right-clicked with nametag and name entered? - if formname == "mobs_texture" - and fields.name - and fields.name ~= "" then + if formname == "mobs_texture" and fields.name and fields.name ~= "" then -- does mob still exist? - if not tex_obj - or not tex_obj:get_luaentity() then - return - end + if not tex_obj or not tex_obj:get_luaentity() then return end -- make sure nametag is being used to name mob local item = player:get_wielded_item() - if item:get_name() ~= "mobs:mob_reset_stick" then - return - end + if item:get_name() ~= "mobs:mob_reset_stick" then return end -- limit name entered to 64 characters long - if fields.name:len() > 64 then - fields.name = fields.name:sub(1, 64) - end + if fields.name:len() > 64 then fields.name = fields.name:sub(1, 64) end -- update texture local self = tex_obj:get_luaentity() @@ -391,17 +362,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) - -- Meat Block + minetest.register_node("mobs:meatblock", { description = S("Meat Block"), tiles = {"mobs_meat_top.png", "mobs_meat_bottom.png", "mobs_meat_side.png"}, paramtype2 = "facedir", - groups = { - choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1 - }, + groups = {choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1}, is_ground_content = false, - sounds = mod_def and default.node_sound_leaves_defaults(), + sounds = mobs.node_sound_dirt_defaults(), on_place = minetest.rotate_node, on_use = minetest.item_eat(20), _mcl_hardness = 0.8, @@ -420,15 +389,14 @@ minetest.register_craft({ }) -- Meat Block (raw) + minetest.register_node("mobs:meatblock_raw", { description = S("Raw Meat Block"), tiles = {"mobs_meat_raw_top.png", "mobs_meat_raw_bottom.png", "mobs_meat_raw_side.png"}, paramtype2 = "facedir", - groups = { - choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1 - }, + groups = {choppy = 1, oddly_breakable_by_hand = 1, axey = 1, handy = 1}, is_ground_content = false, - sounds = mod_def and default.node_sound_leaves_defaults(), + sounds = mobs.node_sound_dirt_defaults(), on_place = minetest.rotate_node, on_use = minetest.item_eat(20), _mcl_hardness = 0.8, diff --git a/init.lua b/init.lua index 70c32a1..61d2ba8 100644 --- a/init.lua +++ b/init.lua @@ -1,13 +1,13 @@ -local path = minetest.get_modpath("mobs") +-- peaceful player privilege --- Peaceful player privilege minetest.register_privilege("peaceful_player", { description = "Prevents Mobs Redo mobs from attacking player", give_to_singleplayer = false }) --- Fallback node +-- fallback node + minetest.register_node("mobs:fallback_node", { description = "Fallback Node", tiles = {"mobs_fallback.png"}, @@ -16,22 +16,20 @@ minetest.register_node("mobs:fallback_node", { drop = "" }) --- Mob API -dofile(path .. "/api.lua") +local path = minetest.get_modpath("mobs") --- Rideable Mobs -dofile(path .. "/mount.lua") +dofile(path .. "/api.lua") -- mob API --- Mob Items -dofile(path .. "/crafts.lua") +dofile(path .. "/mount.lua") -- rideable mobs --- Mob Spawner -dofile(path .. "/spawner.lua") +dofile(path .. "/crafts.lua") -- items and crafts + +dofile(path .. "/spawner.lua") -- mob spawner -- Lucky Blocks + if minetest.get_modpath("lucky_block") then dofile(path .. "/lucky_block.lua") end - print("[MOD] Mobs Redo loaded") diff --git a/lucky_block.lua b/lucky_block.lua index cd249ad..8c95b5b 100644 --- a/lucky_block.lua +++ b/lucky_block.lua @@ -1,6 +1,7 @@ local S = minetest.get_translator("mobs") +-- add lucky blocks lucky_block:add_blocks({ {"dro", {"mobs:meat_raw"}, 5}, @@ -17,8 +18,7 @@ lucky_block:add_blocks({ {"lig"} }) - --- pint sized rune +-- pint sized rune, use on tamed mob to shrink to half-size minetest.register_craftitem(":mobs:pint_sized_rune", { description = S("Pint Sized Rune"), @@ -27,17 +27,13 @@ minetest.register_craftitem(":mobs:pint_sized_rune", { on_use = function(itemstack, user, pointed_thing) - if pointed_thing.type ~= "object" then - return - end + if pointed_thing.type ~= "object" then return end local name = user and user:get_player_name() or "" local tool = user and user:get_wielded_item() local tool_name = tool:get_name() - if tool_name ~= "mobs:pint_sized_rune" then - return - end + if tool_name ~= "mobs:pint_sized_rune" then return end local self = pointed_thing.ref:get_luaentity() @@ -82,11 +78,8 @@ minetest.register_craftitem(":mobs:pint_sized_rune", { self.base_selbox = selbox - self.object:set_properties({ - visual_size = vis_size, - collisionbox = colbox, - selectionbox = selbox - }) + self.object:set_properties( + {visual_size = vis_size, collisionbox = colbox, selectionbox = selbox}) self.pint_size_potion = true @@ -100,6 +93,5 @@ minetest.register_craftitem(":mobs:pint_sized_rune", { minetest.register_craft({ output = "lucky_block:pint_sized_rune", - recipe = {{ "lucky_block:pint_sized_potion", "mobs:protector" }} + recipe = {{"lucky_block:pint_sized_potion", "mobs:protector"}} }) - diff --git a/mod.conf b/mod.conf index 4317e4b..9ba31aa 100644 --- a/mod.conf +++ b/mod.conf @@ -1,4 +1,4 @@ name = mobs description = Adds a mob api for mods to add animals or monsters etc. -optional_depends = default, tnt, invisibility, lucky_block, cmi, toolranks, pathfinder, player_api, mtobjid, visual_harm_1ndicators +optional_depends = default, tnt, invisibility, lucky_block, cmi, toolranks, pathfinder, player_api, mtobjid, visual_harm_1ndicators, mcl_sounds min_minetest_version = 5.0 diff --git a/mount.lua b/mount.lua index fbf1f22..77035c3 100644 --- a/mount.lua +++ b/mount.lua @@ -1,8 +1,10 @@ + -- lib_mount by Blert2112 (edited by TenPlus1) local is_mc2 = minetest.get_modpath("mcl_mobs") -- MineClone2 check -- one of these is needed to ride mobs, otherwise no riding for you + if not minetest.get_modpath("player_api") and not is_mc2 then function mobs.attach() end @@ -14,12 +16,11 @@ if not minetest.get_modpath("player_api") and not is_mc2 then end -- Localise some functions + local abs, cos, floor, sin, sqrt, pi = math.abs, math.cos, math.floor, math.sin, math.sqrt, math.pi --- --- Helper functions --- +-- helper functions local node_ok = function(pos, fallback) @@ -27,9 +28,7 @@ local node_ok = function(pos, fallback) local node = minetest.get_node_or_nil(pos) - if node and minetest.registered_nodes[node.name] then - return node - end + if node and minetest.registered_nodes[node.name] then return node end return {name = fallback} end @@ -39,9 +38,7 @@ local function node_is(entity) if not entity.standing_on then return "other" end - if entity.standing_on == "air" then - return "air" - end + if entity.standing_on == "air" then return "air" end if minetest.get_item_group(entity.standing_on, "lava") ~= 0 then return "lava" @@ -61,13 +58,9 @@ end local function get_sign(i) - i = i or 0 + if not i or i == 0 then return 0 end - if i == 0 then - return 0 - else - return i / abs(i) - end + return i / abs(i) end @@ -89,9 +82,7 @@ local function force_detach(player) local attached_to = player and player:get_attach() - if not attached_to then - return - end + if not attached_to then return end local entity = attached_to:get_luaentity() @@ -115,11 +106,13 @@ local function force_detach(player) player:set_properties({visual_size = {x = 1, y = 1}}) end +-- detach player on leaving minetest.register_on_leaveplayer(function(player) force_detach(player) end) +-- detatch all players on shutdown minetest.register_on_shutdown(function() @@ -130,25 +123,21 @@ minetest.register_on_shutdown(function() end end) +-- detatch player when dead minetest.register_on_dieplayer(function(player) force_detach(player) return true end) +-- find free position to detach player --- Just for correct detaching local function find_free_pos(pos) local check = { - {x = 1, y = 0, z = 0}, - {x = 1, y = 1, z = 0}, - {x = -1, y = 0, z = 0}, - {x = -1, y = 1, z = 0}, - {x = 0, y = 0, z = 1}, - {x = 0, y = 1, z = 1}, - {x = 0, y = 0, z = -1}, - {x = 0, y = 1, z = -1} + {x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, {x = -1, y = 0, z = 0}, + {x = -1, y = 1, z = 0}, {x = 0, y = 0, z = 1}, {x = 0, y = 1, z = 1}, + {x = 0, y = 0, z = -1}, {x = 0, y = 1, z = -1} } for _, c in pairs(check) do @@ -169,8 +158,8 @@ local function find_free_pos(pos) return pos end - -- are we a real player ? + local function is_player(player) if player and type(player) == "userdata" and minetest.is_player(player) then @@ -178,6 +167,7 @@ local function is_player(player) end end +-- attach player to mob entity function mobs.attach(entity, player) @@ -190,9 +180,7 @@ function mobs.attach(entity, player) local rot_view = 0 - if entity.player_rotation.y == 90 then - rot_view = pi / 2 - end + if entity.player_rotation.y == 90 then rot_view = pi / 2 end local attach_at = entity.driver_attach_at local eye_offset = entity.driver_eye_offset @@ -211,10 +199,7 @@ function mobs.attach(entity, player) player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0}) player:set_properties({ - visual_size = { - x = entity.driver_scale.x, - y = entity.driver_scale.y - } + visual_size = {x = entity.driver_scale.x, y = entity.driver_scale.y} }) minetest.after(0.2, function() @@ -232,6 +217,7 @@ function mobs.attach(entity, player) player:set_look_horizontal(entity.object:get_yaw() - rot_view) end +-- detatch player from mob function mobs.detach(player) @@ -250,15 +236,14 @@ function mobs.detach(player) end) end +-- ride mob like car or horse function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) local yaw = entity.object:get_yaw() or 0 local rot_view = 0 - if entity.player_rotation.y == 90 then - rot_view = pi / 2 - end + if entity.player_rotation.y == 90 then rot_view = pi / 2 end local acce_y = 0 local velo = entity.object:get_velocity() ; if not velo then return end @@ -276,9 +261,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) elseif ctrl.down then -- move backwards - if entity.max_speed_reverse == 0 and entity.v == 0 then - return - end + if entity.max_speed_reverse == 0 and entity.v == 0 then return end entity.v = entity.v - entity.accel * dtime end @@ -290,12 +273,8 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) horz = yaw - if ctrl.left then - horz = horz + 0.05 - - elseif ctrl.right then - horz = horz - 0.05 - end + if ctrl.left then horz = horz + 0.05 + elseif ctrl.right then horz = horz - 0.05 end else horz = entity.driver:get_look_horizontal() or 0 end @@ -333,8 +312,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) if ctrl.jump then -- jump (only when standing on solid surface) if velo.y == 0 - and entity.standing_on ~= "air" - and entity.standing_on ~= "ignore" + and entity.standing_on ~= "air" and entity.standing_on ~= "ignore" and minetest.get_item_group(entity.standing_on, "liquid") == 0 then velo.y = velo.y + entity.jump_height acce_y = acce_y + (acce_y * 3) + 1 @@ -346,17 +324,13 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) -- if not moving then set animation and return if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then - if stand_anim then - entity:set_animation(stand_anim) - end + if stand_anim then entity:set_animation(stand_anim) end return end -- set moving animation - if moving_anim then - entity:set_animation(moving_anim) - end + if moving_anim then entity:set_animation(moving_anim) end -- Stop! local s = get_sign(entity.v) @@ -392,9 +366,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) if ni == "air" then - if can_fly == true then - new_acce.y = 0 - end + if can_fly == true then new_acce.y = 0 end elseif ni == "liquid" or ni == "lava" then @@ -441,8 +413,8 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) entity.v2 = v end +-- fly mob in facing direction (by D00Med, edited by TenPlus1) --- directional flying routine by D00Med (edited by TenPlus1) function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim) local ctrl = entity.driver:get_player_control() ; if not ctrl then return end @@ -454,19 +426,13 @@ function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim) if ctrl.up then - entity.object:set_velocity({ - x = dir.x * speed, - y = dir.y * speed + 2, - z = dir.z * speed - }) + entity.object:set_velocity( + {x = dir.x * speed, y = dir.y * speed + 2, z = dir.z * speed}) elseif ctrl.down then - entity.object:set_velocity({ - x = -dir.x * speed, - y = dir.y * speed + 2, - z = -dir.z * speed - }) + entity.object:set_velocity( + {x = -dir.x * speed, y = dir.y * speed + 2, z = -dir.z * speed}) elseif not ctrl.down or ctrl.up or ctrl.jump then entity.object:set_velocity({x = 0, y = -2, z = 0}) @@ -501,11 +467,9 @@ function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim) end end - -- change animation if stopped if velo.x == 0 and velo.y == 0 and velo.z == 0 then - entity:set_animation(stand_anim) + entity:set_animation(stand_anim) -- stopped animation else - -- moving animation - entity:set_animation(moving_anim) + entity:set_animation(moving_anim) -- moving animation end end diff --git a/settingtypes.txt b/settingtypes.txt index 1726bbb..f94ce34 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -66,8 +66,6 @@ mobs_can_hear (Enable Mob hearing) bool true [Pathfinding] # Enable pathfinding (default Enabled) mob_pathfinding_enable (Enable pathfinding) bool true -# Use pathfinder mod if available (default Enabled) -mob_pathfinder_enable (Use pathfinder mod if available) bool true # How long before stuck mobs starts searching (default 3.0) mob_pathfinding_stuck_timeout (How long before stuck mobs start searching) float 3.0 # How long will mob follow path before giving up (default 5.0) diff --git a/spawner.lua b/spawner.lua index 1dd9c88..271cbd6 100644 --- a/spawner.lua +++ b/spawner.lua @@ -1,8 +1,9 @@ -local S = mobs.translate +local S = minetest.get_translator("mobs") +local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99) +-- helper functions --- are we a real player ? local function is_player(player) if player and type(player) == "userdata" and minetest.is_player(player) then @@ -21,8 +22,8 @@ local get_distance = function(a, b) return square(x * x + y * y + z * z) end - -- mob spawner + local spawner_default = "mobs_animal:pumba 10 15 0 0 0" minetest.register_node("mobs:spawner", { @@ -35,6 +36,7 @@ minetest.register_node("mobs:spawner", { is_ground_content = false, _mcl_hardness = 1, _mcl_blast_resistance = 5, + sounds = mobs.node_sound_stone_defaults(), on_construct = function(pos) @@ -56,16 +58,12 @@ minetest.register_node("mobs:spawner", { on_right_click = function(pos, placer) - if minetest.is_protected(pos, placer:get_player_name()) then - return - end + if minetest.is_protected(pos, placer:get_player_name()) then return end end, on_receive_fields = function(pos, formname, fields, sender) - if not fields.text or fields.text == "" then - return - end + if not fields.text or fields.text == "" then return end local meta = minetest.get_meta(pos) local comm = fields.text:split(" ") @@ -76,35 +74,31 @@ minetest.register_node("mobs:spawner", { return end - local mob = comm[1] -- mob to spawn + local mob = comm[1] or "" -- mob to spawn local mlig = tonumber(comm[2]) -- min light local xlig = tonumber(comm[3]) -- max light local num = tonumber(comm[4]) -- total mobs in area local pla = tonumber(comm[5]) -- player distance (0 to disable) local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob - if mob and mob ~= "" and mobs.spawning_mobs[mob] - and num and num >= 0 and num <= 10 - and mlig and mlig >= 0 and mlig <= 15 - and xlig and xlig >= 0 and xlig <= 15 - and pla and pla >= 0 and pla <= 20 - and yof and yof > -10 and yof < 10 then + if mob ~= "" and mobs.spawning_mobs[mob] and num and num >= 0 and num <= 10 + and mlig and mlig >= 0 and mlig <= 15 and xlig and xlig >= 0 and xlig <= 15 + and pla and pla >= 0 and pla <= 20 and yof and yof > -10 and yof < 10 then meta:set_string("command", fields.text) meta:set_string("infotext", S("Spawner Active (@1)", mob)) - else minetest.chat_send_player(name, S("Mob Spawner settings failed!")) minetest.chat_send_player(name, - S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] player_distance[1-20] y_offset[-10 to 10]”")) + S("Syntax: “name min_light[0-14] max_light[0-14] " + .. "max_mobs_in_area[0 to disable] player_distance[1-20] " + .. "y_offset[-10 to 10]”")) end end }) - -local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99) - -- spawner abm + minetest.register_abm({ label = "Mob spawner node", nodenames = {"mobs:spawner"}, @@ -115,9 +109,7 @@ minetest.register_abm({ action = function(pos, node, active_object_count, active_object_count_wider) -- return if too many entities already - if active_object_count_wider >= max_per_block then - return - end + if active_object_count_wider >= max_per_block then return end -- get meta and command local meta = minetest.get_meta(pos) @@ -132,9 +124,7 @@ minetest.register_abm({ local yof = tonumber(comm[6]) or 0 -- if amount is 0 then do nothing - if num == 0 then - return - end + if num == 0 then return end -- are we spawning a registered mob? if not mobs.spawning_mobs[mob] then @@ -152,15 +142,11 @@ minetest.register_abm({ ent = obj:get_luaentity() - if ent and ent.name and ent.name == mob then - count = count + 1 - end + if ent and ent.name and ent.name == mob then count = count + 1 end end -- is there too many of same type? - if count >= num then - return - end + if count >= num then return end -- when player distance above 0, spawn mob if player detected and in range if pla > 0 then @@ -181,22 +167,18 @@ minetest.register_abm({ end -- player not found - if not in_range then - return - end + if not in_range then return end end -- set medium mob usually spawns in (defaults to air) local reg = minetest.registered_entities[mob].fly_in - if not reg or type(reg) == "string" then - reg = {(reg or "air")} - end + if not reg or type(reg) == "string" then reg = {(reg or "air")} end -- find air blocks within 5 nodes of spawner local air = minetest.find_nodes_in_area( - {x = pos.x - 5, y = pos.y + yof, z = pos.z - 5}, - {x = pos.x + 5, y = pos.y + yof, z = pos.z + 5}, reg) + {x = pos.x - 5, y = pos.y + yof, z = pos.z - 5}, + {x = pos.x + 5, y = pos.y + yof, z = pos.z + 5}, reg) -- spawn in random air block if air and #air > 0 then @@ -207,8 +189,7 @@ minetest.register_abm({ pos2.y = pos2.y + 0.5 -- only if light levels are within range - if lig >= mlig and lig <= xlig - and minetest.registered_entities[mob] then + if lig >= mlig and lig <= xlig and minetest.registered_entities[mob] then minetest.add_entity(pos2, mob) end end