1
0
mirror of https://codeberg.org/tenplus1/mobs_redo.git synced 2025-07-20 17:20:23 +02:00

Compare commits

..

19 Commits

Author SHA1 Message Date
c06d071220 allow players with 'protection_bypass' to rename owned tamed mobs 2021-04-07 10:35:36 +01:00
ccbfe93f12 players with protection_bypass can pick up owned animals from other players 2021-04-06 15:26:36 +01:00
6750d176ee tweak damage and protectors 2021-04-05 08:52:48 +01:00
246b2769f7 add level 2 mob protector 2021-04-04 22:25:40 +01:00
34b06df758 add ability to follow group: items 2021-03-23 17:09:26 +00:00
0f1f3b4fb3 simplify mobs floating in water 2021-03-18 20:23:55 +00:00
774ce6671f add 'ignore_invisibility' setting to mob definition 2021-03-10 08:14:42 +00:00
11e1d52cfb replace minetest 5.0 check 2021-02-06 17:10:50 +00:00
c158e84e28 stop grown child mobs sinking into blocks below 2021-02-03 21:29:26 +00:00
10e4dd92a0 spawner spawns mob in it's own medium (air, water etc.) 2021-01-21 11:10:17 +00:00
10053e05a9 update mod.conf info 2021-01-21 10:18:00 +00:00
425cadeb51 improve mount.lua (changes from lib_mount :) 2021-01-21 09:44:31 +00:00
2d1befacb3 nil check 2021-01-19 20:37:42 +00:00
ad2ccc5895 add a few compatibility groups to mob items 2021-01-14 19:24:40 +00:00
754321541a fix mob spawn height (thanks OgelGames) 2021-01-14 10:28:18 +00:00
622abd1486 hopefully fixed death animation crash when player away 2021-01-08 10:16:33 +00:00
55eb893a9a simple swimming fix to stop floaters 2021-01-07 10:42:10 +00:00
76ee3d0b51 add peaceful player privs and settings (thanks sfence) 2021-01-04 12:28:17 +00:00
00ac9efc8c fix global catch sound (thanks SwissalpS) 2021-01-02 20:31:01 +00:00
10 changed files with 312 additions and 213 deletions

273
api.lua
View File

@ -8,12 +8,12 @@ local use_cmi = minetest.global_exists("cmi")
mobs = {
mod = "redo",
version = "20201206",
version = "20210407",
intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {}
}
-- localize math functions
-- localize common functions
local pi = math.pi
local square = math.sqrt
local sin = math.sin
@ -65,6 +65,7 @@ local max_per_block = tonumber(settings:get("max_objects_per_block") or 99)
local mob_nospawn_range = tonumber(settings:get("mob_nospawn_range") or 12)
local active_limit = tonumber(settings:get("mob_active_limit") or 0)
local mob_chance_multiplier = tonumber(settings:get("mob_chance_multiplier") or 1)
local peaceful_player_enabled = settings:get_bool("enable_peaceful_player")
local active_mobs = 0
@ -111,7 +112,8 @@ local mob_class = {
light_damage_min = 14,
light_damage_max = 15,
water_damage = 0,
lava_damage = 0,
lava_damage = 4,
fire_damage = 4,
air_damage = 0,
suffocation = 2,
fall_damage = 1,
@ -163,6 +165,7 @@ local mob_class = {
local mob_class_meta = {__index = mob_class}
-- play sound
function mob_class:mob_sound(sound)
@ -250,9 +253,17 @@ local check_for = function(look_for, look_inside)
for _, str in pairs(look_inside) do
if str == look_for then
return true
end
if str:find("group:") then
local group = str:split(":")[2]
if minetest.get_item_group(look_for, group) ~= 0 then
return true
end
end
end
end
@ -538,12 +549,10 @@ local ray_line_of_sight = function(self, pos1, pos2)
return true
end
-- detect if using minetest 5.0 by searching for permafrost node
local is_50 = minetest.registered_nodes["default:permafrost"]
function mob_class:line_of_sight(pos1, pos2, stepsize)
if is_50 then -- only use if minetest 5.0 is detected
if minetest.raycast then -- only use if minetest 5.0 is detected
return ray_line_of_sight(self, pos1, pos2)
end
@ -562,7 +571,7 @@ function mob_class:attempt_flight_correction(override)
-- 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()
local pos = self.object:get_pos() ; if not pos then return true end
local searchnodes = self.fly_in
if type(searchnodes) == "string" then
@ -571,7 +580,8 @@ function mob_class:attempt_flight_correction(override)
local flyable_nodes = minetest.find_nodes_in_area(
{x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
{x = pos.x + 1, y = pos.y + 1, z = pos.z + 1}, searchnodes)
{x = pos.x + 1, y = pos.y + 0, z = pos.z + 1}, searchnodes)
-- pos.y + 0 hopefully fixes floating swimmers
if #flyable_nodes < 1 then
return false
@ -908,6 +918,7 @@ function mob_class:check_for_death(cmi_cause)
local rot = self.animation.die_rotate and 5
self.attack = nil
self.following = nil
self.v_start = false
self.timer = 0
self.blinktimer = 0
@ -915,7 +926,7 @@ function mob_class:check_for_death(cmi_cause)
self.state = "die"
self.object:set_properties({
pointable = false, collide_with_objects = false,
automatic_rotate = rot,
automatic_rotate = rot, static_save = false
})
self:set_velocity(0)
self:set_animation("die")
@ -973,7 +984,12 @@ local is_node_dangerous = function(self, nodename)
end
if self.lava_damage > 0
and minetest.get_item_group(nodename, "igniter") ~= 0 then
and minetest.get_item_group(nodename, "lava") ~= 0 then
return true
end
if self.fire_damage > 0
and minetest.get_item_group(nodename, "fire") ~= 0 then
return true
end
@ -1059,37 +1075,47 @@ function mob_class:do_env_damage()
local nodef = minetest.registered_nodes[self.standing_in]
-- water
if self.water_damage and nodef.groups.water then
if self.water_damage ~= 0
and nodef.groups.water then
if self.water_damage ~= 0 then
self.health = self.health - self.water_damage
self.health = self.health - self.water_damage
effect(pos, 5, "bubble.png", nil, nil, 1, nil)
effect(pos, 5, "bubble.png", nil, nil, 1, nil)
if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then
return true
end
if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then
return true
end
-- ignition source (fire or lava)
elseif self.lava_damage and nodef.groups.igniter then
-- lava damage
elseif self.lava_damage ~= 0
and nodef.groups.lava then
if self.lava_damage ~= 0 then
self.health = self.health - self.lava_damage
self.health = self.health - self.lava_damage
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then
return true
end
if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then
return true
end
-- damage_per_second node check
elseif nodef.damage_per_second ~= 0 then
-- fire damage
elseif self.fire_damage ~= 0
and nodef.groups.fire then
self.health = self.health - self.fire_damage
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then
return true
end
-- damage_per_second node check (not fire and lava)
elseif nodef.damage_per_second ~= 0
and nodef.groups.lava == 0 and nodef.groups.fire == 0 then
self.health = self.health - nodef.damage_per_second
@ -1303,10 +1329,19 @@ local entity_physics = function(pos, radius)
end
-- can mob see player
local is_invisible = function(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 mobs.invis[clicker:get_player_name()] then
if is_invisible(self, clicker:get_player_name()) then
return false
end
@ -1351,11 +1386,15 @@ function mob_class:breed()
self.on_grown(self)
else
-- jump when fully grown so as not to fall into ground
self.object:set_velocity({
x = 0,
y = self.jump_height,
z = 0
})
-- self.object:set_velocity({
-- x = 0,
-- y = self.jump_height,
-- z = 0
-- })
local pos = self.object:get_pos() ; if not pos then return end
local ent = self.object:get_luaentity()
pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4
self.object:set_pos(pos)
end
end
@ -1455,6 +1494,8 @@ function mob_class:breed()
effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5)
end
pos.y = pos.y + 0.5 -- spawn child a little higher
local mob = minetest.add_entity(pos, self.name)
local ent2 = mob:get_luaentity()
local textures = self.base_texture
@ -1848,6 +1889,23 @@ function mob_class:smart_mobs(s, p, dist, dtime)
end
-- peaceful player privilege support
local function is_peaceful_player(player)
if peaceful_player_enabled then
local player_name = player:get_player_name()
if player_name
and minetest.check_player_privs(player_name, "peaceful_player") then
return true
end
end
return false
end
-- general attack function for all mobs
function mob_class:general_attack()
@ -1874,7 +1932,7 @@ function mob_class:general_attack()
if not damage_enabled
or self.attack_players == false
or (self.owner and self.type ~= "monster")
or mobs.invis[objs[n]:get_player_name()]
or is_invisible(self, objs[n]:get_player_name())
or (self.specific_attack
and not check_for("player", self.specific_attack)) then
objs[n] = nil
@ -1920,7 +1978,8 @@ function mob_class:general_attack()
-- choose closest player to attack that isnt self
if dist ~= 0
and dist < min_dist
and self:line_of_sight(sp, p, 2) == true then
and self:line_of_sight(sp, p, 2) == true
and not is_peaceful_player(player) then
min_dist = dist
min_player = player
end
@ -1952,7 +2011,7 @@ function mob_class:do_runaway_from()
pname = objs[n]:get_player_name()
if mobs.invis[pname]
if is_invisible(self, pname)
or self.owner == pname then
name = ""
@ -2017,7 +2076,7 @@ function mob_class:follow_flop()
for n = 1, #players do
if get_distance(players[n]:get_pos(), s) < self.view_range
and not mobs.invis[ players[n]:get_player_name() ] then
and not is_invisible(self, players[n]:get_player_name()) then
self.following = players[n]
@ -2315,7 +2374,7 @@ function mob_class:do_states(dtime)
or not self.attack:get_pos()
or self.attack:get_hp() <= 0
or (self.attack:is_player()
and mobs.invis[ self.attack:get_player_name() ]) then
and is_invisible(self, self.attack:get_player_name())) then
--print(" ** stop attacking **", dist, self.view_range)
@ -2663,34 +2722,17 @@ function mob_class:falling(pos)
-- sanity check
if not v then return end
local fall_speed = -10 -- gravity
-- don't exceed mob fall speed
if v.y < self.fall_speed then
fall_speed = self.fall_speed
end
local fall_speed = self.fall_speed
-- in water then use liquid viscosity for float/sink speed
if (self.standing_in
and minetest.registered_nodes[self.standing_in].groups.liquid)
or (self.standing_on
and minetest.registered_nodes[self.standing_in].groups.liquid) then
if self.floats == 1 and self.standing_in
and minetest.registered_nodes[self.standing_in].groups.liquid then
local visc = min(
minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
minetest.registered_nodes[self.standing_in].liquid_viscosity, 7) + 1
if self.floats == 1 then
-- floating up
if visc > 0 then
fall_speed = max(1, v.y) / (visc + 1)
end
else
-- sinking down
if visc > 0 then
fall_speed = -(max(1, v.y) / (visc + 1))
end
end
self.object:set_velocity({x = v.x, y = 0.6, z = v.z})
fall_speed = -1.2 / visc
else
-- fall damage onto solid ground
@ -2747,15 +2789,37 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
return true
end
-- is mob protected?
if self.protected and hitter:is_player()
and minetest.is_protected(self.object:get_pos(),
hitter:get_player_name()) then
-- is mob protected
if self.protected then
minetest.chat_send_player(hitter:get_player_name(),
S("Mob has been protected!"))
-- did player hit mob and if so is it in protected area
if hitter:is_player() then
return true
local player_name = hitter:get_player_name()
if player_name ~= self.owner
and minetest.is_protected(self.object:get_pos(), player_name) then
minetest.chat_send_player(hitter:get_player_name(),
S("Mob has been protected!"))
return true
end
-- if protection is on level 2 then dont let arrows harm mobs
elseif self.protected == 2 then
local ent = hitter and hitter:get_luaentity()
if ent and ent._is_arrow then
return true -- arrow entity
elseif not ent then
return true -- non entity
end
end
end
local weapon = hitter:get_wielded_item()
@ -2787,7 +2851,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
end
damage = damage + (tool_capabilities.damage_groups[group] or 0)
* tmp * ((armor[group] or 0) / 100.0)
* tmp * ((armor[group] or 0) / 100.0)
end
end
@ -2967,7 +3031,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
and self.child == false
and self.attack_players == true
and hitter:get_player_name() ~= self.owner
and not mobs.invis[ name ]
and not is_invisible(self, name)
and self.object ~= hitter then
-- attack whoever punched mob
@ -3054,6 +3118,7 @@ function mob_class:mob_staticdata()
if t ~= "function"
and t ~= "nil"
and t ~= "userdata"
and _ ~= "object"
and _ ~= "_cmi_components" then
tmp[_] = self[_]
end
@ -3123,8 +3188,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
def.textures = {def.textures}
end
self.base_texture = def.textures and
def.textures[random(#def.textures)]
self.base_texture = def.textures and def.textures[random(#def.textures)]
self.base_mesh = def.mesh
self.base_size = self.visual_size
self.base_colbox = self.collisionbox
@ -3306,6 +3370,8 @@ function mob_class:on_step(dtime, moveresult)
}}
}]]
if self.state == "die" then return end ----------------
if use_cmi then
cmi.notify_step(self.object, dtime)
end
@ -3529,6 +3595,7 @@ minetest.register_entity(name, setmetatable({
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,
suffocation = def.suffocation,
fall_damage = def.fall_damage,
@ -3587,6 +3654,7 @@ minetest.register_entity(name, setmetatable({
pushable = def.pushable,
stay_near = def.stay_near,
randomly_turn = def.randomly_turn ~= false,
ignore_invisibility = def.ignore_invisibility,
on_spawn = def.on_spawn,
@ -3681,9 +3749,6 @@ local can_spawn = function(pos, name)
end
end
-- spawn mob 1/2 node above ground
pos.y = pos.y + 0.5
-- tweak X/Z spawn pos
if width_x % 2 == 0 then
pos.x = pos.x + 0.5
@ -3948,15 +4013,15 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
end
end
local ent = minetest.registered_entities[name]
-- should we check mob area for obstructions ?
if mob_area_spawn ~= true then
-- do we have enough height clearance to spawn mob?
local ent = minetest.registered_entities[name]
local height = max(1, math.ceil(
(ent.collisionbox[5] or 0.25) - (ent.collisionbox[2] or -0.25) - 1))
local height = max(0, ent.collisionbox[5] - ent.collisionbox[2])
for n = 0, height do
for n = 0, floor(height) do
local pos2 = {x = pos.x, y = pos.y + n, z = pos.z}
@ -3972,6 +4037,9 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
if pos then
-- adjust for mob collision box
pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4
local mob = minetest.add_entity(pos, name)
-- print("[mobs] Spawned " .. name .. " at "
@ -4431,8 +4499,9 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net,
return false
end
-- cannot pick up if not owner
if self.owner ~= name and force_take == false then
-- cannot pick up if not owner (unless player has protection_bypass priv)
if not minetest.check_player_privs(name, "protection_bypass")
and self.owner ~= name and force_take == false then
minetest.chat_send_player(name, S("@1 is owner!", self.owner))
@ -4503,10 +4572,10 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net,
minetest.add_item(clicker:get_pos(), new_stack)
end
remove_mob(self, true)
self:mob_sound("default_place_node_hard")
remove_mob(self, true)
return new_stack
-- when chance above fails or set to 0, miss!
@ -4533,19 +4602,21 @@ function mobs:protect(self, clicker)
local name = clicker:get_player_name()
local tool = clicker:get_wielded_item()
local tool_name = tool:get_name()
if tool:get_name() ~= "mobs:protector" then
if tool_name ~= "mobs:protector"
and tool_name ~= "mobs:protector2" then
return false
end
if self.tamed == false then
if not self.tamed then
minetest.chat_send_player(name, S("Not tamed!"))
return true -- false
return true
end
if self.protected == true then
if self.protected then
minetest.chat_send_player(name, S("Already protected!"))
return true -- false
return true
end
if not mobs.is_creative(clicker:get_player_name()) then
@ -4553,9 +4624,15 @@ function mobs:protect(self, clicker)
clicker:set_wielded_item(tool)
end
self.protected = true
-- set protection level
if tool_name == "mobs:protector" then
self.protected = true
else
self.protected = 2 ; self.fire_damage = 0
end
local pos = self.object:get_pos()
pos.y = pos.y + self.collisionbox[2] + 0.5
effect(self.object:get_pos(), 25, "mobs_protect_particle.png",
@ -4615,7 +4692,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + (
(CHILD_GROW_TIME - self.hornytimer) * 0.1)
print ("====", self.hornytimer)
--print ("====", self.hornytimer)
return true
end
@ -4653,12 +4730,12 @@ print ("====", self.hornytimer)
end
local item = clicker:get_wielded_item()
local name = clicker:get_player_name()
-- if mob has been tamed you can name it with a nametag
if item:get_name() == "mobs:nametag"
and clicker:get_player_name() == self.owner then
local name = clicker:get_player_name()
and (name == self.owner
or minetest.check_player_privs(name, "protection_bypass")) then
-- store mob and nametag stack in external variables
mob_obj[name] = self

View File

@ -66,7 +66,10 @@ functions needed for the mob to work properly which contains the following:
water.
'air_damage' holds damage per second inflicted to mob when standing in air.
'lava_damage' holds the damage per second inflicted to mobs when standing
in lava or fire or an ignition source.
in lava.
'fire_damage' holds the damage per second inflicted to mobs when standing
in fire.
'light_damage' holds the damage per second inflicted to mobs when light
level is between the min and max values below
'light_damage_min' minimum light value when mob is affected (default: 14)
@ -76,7 +79,7 @@ functions needed for the mob to work properly which contains the following:
'floats' when set to 1 mob will float in water, 0 has them sink.
'follow' mobs follow player when holding any of the items which appear
on this table, the same items can be fed to a mob to tame or
breed e.g. {"farming:wheat", "default:apple"}
breed e.g. {"farming:wheat", "default:apple", "group:fish"}
'reach' is how far the mob can attack player when standing
nearby, default is 3 nodes.
@ -131,6 +134,8 @@ functions needed for the mob to work properly which contains the following:
e.g. {"player", "mobs_animal:chicken"}.
'runaway_from' contains a table with mob names to run away from, add
"player" to list to runaway from player also.
'ignore_invisibility' When true mob will still be able to see and attack
player even if invisible (invisibility mod only).
'blood_amount' contains the number of blood droplets to appear when
mob is hit.
'blood_texture' has the texture name to use for droplets e.g.

View File

@ -5,7 +5,7 @@ local S = mobs.intllib
minetest.register_craftitem("mobs:nametag", {
description = S("Name Tag"),
inventory_image = "mobs_nametag.png",
groups = {flammable = 2}
groups = {flammable = 2, nametag = 1}
})
if minetest.get_modpath("dye") and minetest.get_modpath("farming") then
@ -20,7 +20,7 @@ end
minetest.register_craftitem("mobs:leather", {
description = S("Leather"),
inventory_image = "mobs_leather.png",
groups = {flammable = 2}
groups = {flammable = 2, leather = 1}
})
-- raw meat
@ -115,11 +115,27 @@ minetest.register_craft({
}
})
-- level 2 protection rune
minetest.register_craftitem("mobs:protector2", {
description = S("Mob Protection Rune (Level 2)"),
inventory_image = "mobs_protector2.png",
groups = {flammable = 2}
})
minetest.register_craft({
output = "mobs:protector2",
recipe = {
{"mobs:protector", "default:mese_crystal", "mobs:protector"},
{"default:mese_crystal", "default:diamondblock", "default:mese_crystal"},
{"mobs:protector", "default:mese_crystal", "mobs:protector"}
}
})
-- saddle
minetest.register_craftitem("mobs:saddle", {
description = S("Saddle"),
inventory_image = "mobs_saddle.png",
groups = {flammable = 2}
groups = {flammable = 2, saddle = 1}
})
minetest.register_craft({

View File

@ -1,6 +1,12 @@
local path = minetest.get_modpath("mobs")
-- Peaceful player privilege
minetest.register_privilege("peaceful_player", {
description = "Prevents Mobs Redo mobs from attacking player",
give_to_singleplayer = false
})
-- Mob API
dofile(path .. "/api.lua")

View File

@ -1 +1,4 @@
name = mobs
depends = default
optional_depends = tnt, dye, farming, invisibility, intllib, lucky_block, cmi, toolranks
description = Adds a mob api for mods to add animals or monsters etc.

195
mount.lua
View File

@ -1,9 +1,7 @@
-- lib_mount by Blert2112 (edited by TenPlus1)
local enable_crash = false
local crash_threshold = 6.5 -- ignored if enable_crash=false
local abs, cos, floor, sin, sqrt, pi =
math.abs, math.cos, math.floor, math.sin, math.sqrt, math.pi
------------------------------------------------------------------------------
--
@ -11,7 +9,6 @@ local crash_threshold = 6.5 -- ignored if enable_crash=false
--
local node_ok = function(pos, fallback)
fallback = fallback or mobs.fallback_node
local node = minetest.get_node_or_nil(pos)
@ -25,7 +22,6 @@ end
local function node_is(pos)
local node = node_ok(pos)
if node.name == "air" then
@ -49,33 +45,30 @@ end
local function get_sign(i)
i = i or 0
if i == 0 then
return 0
else
return i / math.abs(i)
return i / abs(i)
end
end
local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
local x = -sin(yaw) * v
local z = cos(yaw) * v
return {x = x, y = y, z = z}
end
local function get_v(v)
return math.sqrt(v.x * v.x + v.z * v.z)
return sqrt(v.x * v.x + v.z * v.z)
end
local function force_detach(player)
local attached_to = player:get_attach()
if not attached_to then
@ -86,21 +79,19 @@ local function force_detach(player)
if entity and entity.driver
and entity.driver == player then
entity.driver = nil
end
player:set_detach()
default.player_attached[player:get_player_name()] = false
player_api.player_attached[player:get_player_name()] = false
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
default.player_set_animation(player, "stand" , 30)
player:set_properties({visual_size = {x = 1, y = 1} })
player_api.set_animation(player, "stand", 30)
player:set_properties({visual_size = {x = 1, y = 1}})
end
-------------------------------------------------------------------------------
minetest.register_on_leaveplayer(function(player)
force_detach(player)
end)
@ -119,10 +110,37 @@ end)
-------------------------------------------------------------------------------
-- 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}
}
for _, c in pairs(check) do
local npos = {x = pos.x + c.x, y = pos.y + c.y, z = pos.z + c.z}
local node = minetest.get_node_or_nil(npos)
if node and node.name then
local def = minetest.registered_nodes[node.name]
if def and not def.walkable and
def.liquidtype == "none" then
return npos
end
end
end
return pos
end
-------------------------------------------------------------------------------
function mobs.attach(entity, player)
local attach_at, eye_offset = {}, {}
entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0}
entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0}
entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0}
@ -131,17 +149,17 @@ function mobs.attach(entity, player)
local rot_view = 0
if entity.player_rotation.y == 90 then
rot_view = math.pi / 2
rot_view = pi / 2
end
attach_at = entity.driver_attach_at
eye_offset = entity.driver_eye_offset
local attach_at = entity.driver_attach_at
local eye_offset = entity.driver_eye_offset
entity.driver = player
force_detach(player)
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
default.player_attached[player:get_player_name()] = true
player_api.player_attached[player:get_player_name()] = true
player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
player:set_properties({
@ -151,46 +169,36 @@ function mobs.attach(entity, player)
}
})
minetest.after(0.2, function(name)
local player = minetest.get_player_by_name(name)
if player then
default.player_set_animation(player, "sit" , 30)
minetest.after(0.2, function()
if player and player:is_player() then
player_api.set_animation(player, "sit", 30)
end
end, player:get_player_name())
end)
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
end
function mobs.detach(player, offset)
function mobs.detach(player)
force_detach(player)
default.player_set_animation(player, "stand" , 30)
local pos = player:get_pos()
pos = {
x = pos.x + offset.x,
y = pos.y + 0.2 + offset.y,
z = pos.z + offset.z
}
minetest.after(0.1, function(name, pos)
local player = minetest.get_player_by_name(name)
if player then
minetest.after(0.1, function()
if player and player:is_player() then
local pos = find_free_pos(player:get_pos())
pos.y = pos.y + 0.5
player:set_pos(pos)
end
end, player:get_player_name(), pos)
end)
end
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
local yaw = entity.object:get_yaw() or 0
local rot_steer, rot_view = math.pi/2, 0
local rot_view = 0
if entity.player_rotation.y == 90 then
rot_steer, rot_view = 0, math.pi/2
rot_view = pi / 2
end
local acce_y = 0
@ -200,19 +208,14 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- process controls
if entity.driver then
--print ("---velo", get_v(velo))
local ctrl = entity.driver:get_player_control()
-- move forwards
if ctrl.up then
entity.v = entity.v + entity.accel / 10
-- move backwards
elseif ctrl.down then
if entity.max_speed_reverse == 0 and entity.v == 0 then
return
end
@ -220,12 +223,24 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
entity.v = entity.v - entity.accel / 10
end
-- fix mob rotation
local horz = entity.driver:get_look_horizontal() or 0
-- mob rotation
local horz
if entity.alt_turn == true then
horz = yaw
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
entity.object:set_yaw(horz - entity.rotate)
if can_fly then
-- fly up
if ctrl.jump then
velo.y = velo.y + 1
@ -245,9 +260,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
velo.y = velo.y + 0.1
if velo.y > 0 then velo.y = 0 end
end
else
-- jump
if ctrl.jump then
@ -261,7 +274,6 @@ 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
mobs:set_animation(entity, stand_anim)
end
@ -280,7 +292,6 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
entity.v = entity.v - 0.02 * s
if s ~= get_sign(entity.v) then
entity.object:set_velocity({x = 0, y = 0, z = 0})
entity.v = 0
return
@ -293,14 +304,15 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
max_spd = entity.max_speed_forward
end
if math.abs(entity.v) > max_spd then
if abs(entity.v) > max_spd then
entity.v = entity.v - get_sign(entity.v)
end
-- Set position, velocity and acceleration
local p = entity.object:get_pos()
local new_velo
local new_acce = {x = 0, y = -9.8, z = 0}
if not p then return end
local new_acce = {x = 0, y = -9.81, z = 0}
p.y = p.y - 0.5
@ -308,23 +320,18 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
local v = entity.v
if ni == "air" then
if can_fly == true then
new_acce.y = 0
end
elseif ni == "liquid" or ni == "lava" then
if ni == "lava" and entity.lava_damage ~= 0 then
entity.lava_counter = (entity.lava_counter or 0) + dtime
if entity.lava_counter > 1 then
minetest.sound_play("default_punch", {
object = entity.object,
max_hear_distance = 5
}, true)
})
entity.object:punch(entity.object, 1.0, {
full_punch_interval = 1.0,
@ -335,14 +342,12 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end
end
if entity.terrain_type == 2
or entity.terrain_type == 3 then
local terrain_type = entity.terrain_type
if terrain_type == 2 or terrain_type == 3 then
new_acce.y = 0
p.y = p.y + 1
if node_is(p) == "liquid" then
if velo.y >= 5 then
velo.y = 5
elseif velo.y < 0 then
@ -351,9 +356,11 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
new_acce.y = 5
end
else
if math.abs(velo.y) < 1 then
if abs(velo.y) < 1 then
local pos = entity.object:get_pos()
pos.y = math.floor(pos.y) + 0.5
if not pos then return end
pos.y = floor(pos.y) + 0.5
entity.object:set_pos(pos)
velo.y = 0
end
@ -363,46 +370,22 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end
end
new_velo = get_velocity(v, entity.object:get_yaw() - rot_view, velo.y)
local new_velo = get_velocity(v, yaw - rot_view, velo.y)
new_acce.y = new_acce.y + acce_y
entity.object:set_velocity(new_velo)
entity.object:set_acceleration(new_acce)
-- CRASH!
if enable_crash then
local intensity = entity.v2 - v
if intensity >= crash_threshold then
--print("----------- crash", intensity)
entity.object:punch(entity.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = intensity}
}, nil)
end
end
entity.v2 = v
end
-- directional flying routine by D00Med (edited by TenPlus1)
function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
local ctrl = entity.driver:get_player_control()
local velo = entity.object:get_velocity()
local dir = entity.driver:get_look_dir()
local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
local rot_steer, rot_view = math.pi / 2, 0
if entity.player_rotation.y == 90 then
rot_steer, rot_view = 0, math.pi / 2
end
if ctrl.up then
entity.object:set_velocity({
@ -414,7 +397,7 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
elseif ctrl.down then
entity.object:set_velocity({
x = -dir.x * speed,
y = dir.y * speed + 2,
y = dir.y * speed + 2,
z = -dir.z * speed
})
@ -422,11 +405,10 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
entity.object:set_velocity({x = 0, y = -2, z = 0})
end
entity.object:set_yaw(yaw + math.pi + math.pi / 2 - entity.rotate)
entity.object:set_yaw(yaw + pi + pi / 2 - entity.rotate)
-- firing arrows
if ctrl.LMB and ctrl.sneak and shoots then
local pos = entity.object:get_pos()
local obj = minetest.add_entity({
x = pos.x + 0 + dir.x * 2.5,
@ -438,8 +420,8 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
ent.switch = 1 -- for mob specific arrows
ent.owner_id = tostring(entity.object) -- so arrows dont hurt entity you are riding
local vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
local yaw = entity.driver:get_look_horizontal()
obj:set_yaw(yaw + math.pi / 2)
yaw = entity.driver:get_look_horizontal()
obj:set_yaw(yaw + pi / 2)
obj:set_velocity(vec)
else
obj:remove()
@ -448,7 +430,6 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
-- change animation if stopped
if velo.x == 0 and velo.y == 0 and velo.z == 0 then
mobs:set_animation(entity, stand_anim)
else
-- moving animation

View File

@ -23,6 +23,7 @@ Lucky Blocks: 9
Changelog:
- 1.55 - Add 'peaceful_player' privelage and setting so mobs don't attack specific players (thanks sfence)
- 1.54 - Simplified animal breeding function, added editable settings (thanks Wuzzy), Child mobs now take 20 mins to grow up, reverted to simple mob spawning with setting to use area checks, on_flop added, air_damage added.
- 1.53 - Added 'on_map_load' settings to mobs:spawn so that mobs will only spawn when new areas of map are loaded.
- 1.52 - Added 'mob_active_limit' in settings to set number of mobs in game,

View File

@ -36,3 +36,6 @@ mob_active_limit (Mob Active Limit) float 0
# Enables area check when spawning mobs
mob_area_spawn (Mob Area Spawn) bool false
# Enable peaceful player attack prevention
enable_peaceful_player (Mobs do not attack peaceful player without reason) bool false

View File

@ -23,9 +23,9 @@ minetest.register_node("mobs:spawner", {
-- text entry formspec
meta:set_string("formspec",
"size[9,3.5]"
"size[10,3.5]"
.. "label[0.15,0.5;" .. minetest.formspec_escape(head) .. "]"
.. "field[1,2.5;7.5,0.8;text;" .. S("Command:")
.. "field[1,2.5;8.5,0.8;text;" .. S("Command:")
.. ";${command}]")
meta:set_string("infotext", S("Spawner Not Active (enter settings)"))
@ -162,10 +162,17 @@ minetest.register_abm({
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
-- 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}, {"air"})
{x = pos.x + 5, y = pos.y + yof, z = pos.z + 5}, reg)
-- spawn in random air block
if air and #air > 0 then

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B