mirror of
https://codeberg.org/tenplus1/mobs_redo.git
synced 2025-07-19 16:50:25 +02:00
Compare commits
16 Commits
d12576f0c8
...
10e4dd92a0
Author | SHA1 | Date | |
---|---|---|---|
10e4dd92a0 | |||
10053e05a9 | |||
425cadeb51 | |||
2d1befacb3 | |||
ad2ccc5895 | |||
754321541a | |||
622abd1486 | |||
55eb893a9a | |||
76ee3d0b51 | |||
00ac9efc8c | |||
bf32a09e5e | |||
9489ff6965 | |||
1dfd7e1af1 | |||
4a6518eeba | |||
a4d2918383 | |||
bdea826b7c |
181
api.lua
181
api.lua
@ -8,7 +8,7 @@ local use_cmi = minetest.global_exists("cmi")
|
|||||||
|
|
||||||
mobs = {
|
mobs = {
|
||||||
mod = "redo",
|
mod = "redo",
|
||||||
version = "20201029",
|
version = "20210114",
|
||||||
intllib = S,
|
intllib = S,
|
||||||
invis = minetest.global_exists("invisibility") and invisibility or {}
|
invis = minetest.global_exists("invisibility") and invisibility or {}
|
||||||
}
|
}
|
||||||
@ -58,12 +58,14 @@ local mobs_drop_items = settings:get_bool("mobs_drop_items") ~= false
|
|||||||
local mobs_griefing = settings:get_bool("mobs_griefing") ~= false
|
local mobs_griefing = settings:get_bool("mobs_griefing") ~= false
|
||||||
local spawn_protected = settings:get_bool("mobs_spawn_protected") ~= false
|
local spawn_protected = settings:get_bool("mobs_spawn_protected") ~= false
|
||||||
local remove_far = settings:get_bool("remove_far_mobs") ~= false
|
local remove_far = settings:get_bool("remove_far_mobs") ~= false
|
||||||
|
local mob_area_spawn = settings:get_bool("mob_area_spawn")
|
||||||
local difficulty = tonumber(settings:get("mob_difficulty")) or 1.0
|
local difficulty = tonumber(settings:get("mob_difficulty")) or 1.0
|
||||||
local show_health = settings:get_bool("mob_show_health") ~= false
|
local show_health = settings:get_bool("mob_show_health") ~= false
|
||||||
local max_per_block = tonumber(settings:get("max_objects_per_block") or 99)
|
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 mob_nospawn_range = tonumber(settings:get("mob_nospawn_range") or 12)
|
||||||
local active_limit = tonumber(settings:get("mob_active_limit") or 0)
|
local active_limit = tonumber(settings:get("mob_active_limit") or 0)
|
||||||
local mob_chance_multiplier = tonumber(settings:get("mob_chance_multiplier") or 1)
|
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
|
local active_mobs = 0
|
||||||
|
|
||||||
|
|
||||||
@ -111,6 +113,7 @@ local mob_class = {
|
|||||||
light_damage_max = 15,
|
light_damage_max = 15,
|
||||||
water_damage = 0,
|
water_damage = 0,
|
||||||
lava_damage = 0,
|
lava_damage = 0,
|
||||||
|
air_damage = 0,
|
||||||
suffocation = 2,
|
suffocation = 2,
|
||||||
fall_damage = 1,
|
fall_damage = 1,
|
||||||
fall_speed = -10, -- must be lower than -2 (default: -10)
|
fall_speed = -10, -- must be lower than -2 (default: -10)
|
||||||
@ -276,10 +279,10 @@ function mob_class:set_velocity(v)
|
|||||||
c_x, c_y = unpack(self:collision())
|
c_x, c_y = unpack(self:collision())
|
||||||
end
|
end
|
||||||
|
|
||||||
local yaw = (self.object:get_yaw() or 0) + self.rotate
|
local yaw = (self.object:get_yaw() or 0) + (self.rotate or 0)
|
||||||
|
|
||||||
-- nil check for velocity
|
-- nil check for velocity
|
||||||
v = v or 0
|
v = v or 0.01
|
||||||
|
|
||||||
-- check if standing in liquid with max viscosity of 7
|
-- check if standing in liquid with max viscosity of 7
|
||||||
local visc = min(minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
|
local visc = min(minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
|
||||||
@ -291,8 +294,8 @@ function mob_class:set_velocity(v)
|
|||||||
v = v / (visc + 1)
|
v = v / (visc + 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- set velocity with hard limit of 10
|
-- set velocity
|
||||||
local vel = self.object:get_velocity()
|
local vel = self.object:get_velocity() or 0
|
||||||
|
|
||||||
local new_vel = {
|
local new_vel = {
|
||||||
x = (sin(yaw) * -v) + c_x,
|
x = (sin(yaw) * -v) + c_x,
|
||||||
@ -560,7 +563,7 @@ function mob_class:attempt_flight_correction(override)
|
|||||||
|
|
||||||
-- We are not flying in what we are supposed to.
|
-- We are not flying in what we are supposed to.
|
||||||
-- See if we can find intended flight medium and return to it
|
-- 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
|
local searchnodes = self.fly_in
|
||||||
|
|
||||||
if type(searchnodes) == "string" then
|
if type(searchnodes) == "string" then
|
||||||
@ -569,7 +572,8 @@ function mob_class:attempt_flight_correction(override)
|
|||||||
|
|
||||||
local flyable_nodes = minetest.find_nodes_in_area(
|
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},
|
||||||
{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
|
if #flyable_nodes < 1 then
|
||||||
return false
|
return false
|
||||||
@ -828,6 +832,11 @@ end
|
|||||||
-- check if mob is dead or only hurt
|
-- check if mob is dead or only hurt
|
||||||
function mob_class:check_for_death(cmi_cause)
|
function mob_class:check_for_death(cmi_cause)
|
||||||
|
|
||||||
|
-- We dead already
|
||||||
|
if self.state == "die" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
-- has health actually changed?
|
-- has health actually changed?
|
||||||
if self.health == self.old_health and self.health > 0 then
|
if self.health == self.old_health and self.health > 0 then
|
||||||
return false
|
return false
|
||||||
@ -877,7 +886,7 @@ function mob_class:check_for_death(cmi_cause)
|
|||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
-- execute custom death function
|
-- execute custom death function
|
||||||
if self.on_die then
|
if pos and self.on_die then
|
||||||
|
|
||||||
self:on_die(pos)
|
self:on_die(pos)
|
||||||
|
|
||||||
@ -897,27 +906,26 @@ function mob_class:check_for_death(cmi_cause)
|
|||||||
|
|
||||||
local frames = self.animation.die_end - self.animation.die_start
|
local frames = self.animation.die_end - self.animation.die_start
|
||||||
local speed = self.animation.die_speed or 15
|
local speed = self.animation.die_speed or 15
|
||||||
local length = max(frames / speed, 0)
|
local length = max((frames / speed), 0)
|
||||||
|
local rot = self.animation.die_rotate and 5
|
||||||
|
|
||||||
self.attack = nil
|
self.attack = nil
|
||||||
|
self.following = nil
|
||||||
self.v_start = false
|
self.v_start = false
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
self.blinktimer = 0
|
self.blinktimer = 0
|
||||||
self.passive = true
|
self.passive = true
|
||||||
self.state = "die"
|
self.state = "die"
|
||||||
|
self.object:set_properties({
|
||||||
|
pointable = false, collide_with_objects = false,
|
||||||
|
automatic_rotate = rot, static_save = false
|
||||||
|
})
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
self:set_animation("die")
|
self:set_animation("die")
|
||||||
|
|
||||||
minetest.after(length, function(self)
|
minetest.after(length, function(self)
|
||||||
|
|
||||||
if use_cmi and self.object:get_luaentity() then
|
if self.object:get_luaentity() then
|
||||||
cmi.notify_die(self.object, cmi_cause)
|
|
||||||
end
|
|
||||||
|
|
||||||
remove_mob(self, true)
|
|
||||||
|
|
||||||
end, self)
|
|
||||||
else
|
|
||||||
|
|
||||||
if use_cmi then
|
if use_cmi then
|
||||||
cmi.notify_die(self.object, cmi_cause)
|
cmi.notify_die(self.object, cmi_cause)
|
||||||
@ -925,8 +933,20 @@ function mob_class:check_for_death(cmi_cause)
|
|||||||
|
|
||||||
remove_mob(self, true)
|
remove_mob(self, true)
|
||||||
end
|
end
|
||||||
|
end, self)
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
elseif pos then -- otherwise remove mod and show particle effect
|
||||||
|
|
||||||
|
if use_cmi then
|
||||||
|
cmi.notify_die(self.object, cmi_cause)
|
||||||
|
end
|
||||||
|
|
||||||
|
remove_mob(self, true)
|
||||||
|
|
||||||
effect(pos, 20, "tnt_smoke.png")
|
effect(pos, 20, "tnt_smoke.png")
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -1084,6 +1104,19 @@ function mob_class:do_env_damage()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- air damage
|
||||||
|
if self.air_damage ~= 0 and self.standing_in == "air" then
|
||||||
|
|
||||||
|
self.health = self.health - self.air_damage
|
||||||
|
|
||||||
|
effect(pos, 3, "bubble.png", 1, 1, 1, 0.2)
|
||||||
|
|
||||||
|
if self:check_for_death({type = "environment",
|
||||||
|
pos = pos, node = self.standing_in}) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- is mob light sensative, or scared of the dark :P
|
-- is mob light sensative, or scared of the dark :P
|
||||||
if self.light_damage ~= 0 then
|
if self.light_damage ~= 0 then
|
||||||
|
|
||||||
@ -1290,16 +1323,20 @@ function mob_class:follow_holding(clicker)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Thanks Wuzzy for the following editable settings
|
||||||
|
local HORNY_TIME = 30
|
||||||
|
local HORNY_AGAIN_TIME = 300
|
||||||
|
local CHILD_GROW_TIME = 60 * 20 -- 20 minutes
|
||||||
|
|
||||||
-- find two animals of same type and breed if nearby and horny
|
-- find two animals of same type and breed if nearby and horny
|
||||||
function mob_class:breed()
|
function mob_class:breed()
|
||||||
|
|
||||||
-- child takes 240 seconds before growing into adult
|
-- child takes a long time before growing into adult
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
|
|
||||||
self.hornytimer = self.hornytimer + 1
|
self.hornytimer = self.hornytimer + 1
|
||||||
|
|
||||||
if self.hornytimer > 240 then
|
if self.hornytimer > CHILD_GROW_TIME then
|
||||||
|
|
||||||
self.child = false
|
self.child = false
|
||||||
self.hornytimer = 0
|
self.hornytimer = 0
|
||||||
@ -1328,14 +1365,14 @@ function mob_class:breed()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- horny animal can mate for 40 seconds,
|
-- horny animal can mate for HORNY_TIME seconds,
|
||||||
-- afterwards horny animal cannot mate again for 200 seconds
|
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
|
||||||
if self.horny == true
|
if self.horny == true
|
||||||
and self.hornytimer < 240 then
|
and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then
|
||||||
|
|
||||||
self.hornytimer = self.hornytimer + 1
|
self.hornytimer = self.hornytimer + 1
|
||||||
|
|
||||||
if self.hornytimer >= 240 then
|
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
|
||||||
self.hornytimer = 0
|
self.hornytimer = 0
|
||||||
self.horny = false
|
self.horny = false
|
||||||
end
|
end
|
||||||
@ -1343,7 +1380,7 @@ function mob_class:breed()
|
|||||||
|
|
||||||
-- find another same animal who is also horny and mate if nearby
|
-- find another same animal who is also horny and mate if nearby
|
||||||
if self.horny == true
|
if self.horny == true
|
||||||
and self.hornytimer <= 40 then
|
and self.hornytimer <= HORNY_TIME then
|
||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
@ -1351,7 +1388,6 @@ function mob_class:breed()
|
|||||||
"heart.png", 3, 4, 1, 0.1)
|
"heart.png", 3, 4, 1, 0.1)
|
||||||
|
|
||||||
local objs = minetest.get_objects_inside_radius(pos, 3)
|
local objs = minetest.get_objects_inside_radius(pos, 3)
|
||||||
local num = 0
|
|
||||||
local ent
|
local ent
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
@ -1380,18 +1416,20 @@ function mob_class:breed()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if ent
|
-- found another similar horny animal that isn't self?
|
||||||
|
if ent and ent.object ~= self.object
|
||||||
and canmate == true
|
and canmate == true
|
||||||
and ent.horny == true
|
and ent.horny == true
|
||||||
and ent.hornytimer <= 40 then
|
and ent.hornytimer <= HORNY_TIME then
|
||||||
num = num + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- found your mate? then have a baby
|
local pos2 = ent.object:get_pos()
|
||||||
if num > 1 then
|
|
||||||
|
|
||||||
self.hornytimer = 41
|
-- Have mobs face one another
|
||||||
ent.hornytimer = 41
|
yaw_to_pos(self, pos2)
|
||||||
|
yaw_to_pos(ent, self.object:get_pos())
|
||||||
|
|
||||||
|
self.hornytimer = HORNY_TIME + 1
|
||||||
|
ent.hornytimer = HORNY_TIME + 1
|
||||||
|
|
||||||
-- have we reached active mob limit
|
-- have we reached active mob limit
|
||||||
if active_limit > 0 and active_mobs >= active_limit then
|
if active_limit > 0 and active_mobs >= active_limit then
|
||||||
@ -1459,8 +1497,6 @@ function mob_class:breed()
|
|||||||
ent2.owner = self.owner
|
ent2.owner = self.owner
|
||||||
end, self, ent)
|
end, self, ent)
|
||||||
|
|
||||||
num = 0
|
|
||||||
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1815,6 +1851,23 @@ function mob_class:smart_mobs(s, p, dist, dtime)
|
|||||||
end
|
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
|
-- general attack function for all mobs
|
||||||
function mob_class:general_attack()
|
function mob_class:general_attack()
|
||||||
|
|
||||||
@ -1887,7 +1940,8 @@ function mob_class:general_attack()
|
|||||||
-- choose closest player to attack that isnt self
|
-- choose closest player to attack that isnt self
|
||||||
if dist ~= 0
|
if dist ~= 0
|
||||||
and dist < min_dist
|
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_dist = dist
|
||||||
min_player = player
|
min_player = player
|
||||||
end
|
end
|
||||||
@ -2005,10 +2059,11 @@ function mob_class:follow_flop()
|
|||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- stop following player if not holding specific item
|
-- stop following player if not holding specific item or mob is horny
|
||||||
if self.following
|
if self.following
|
||||||
and self.following:is_player()
|
and self.following:is_player()
|
||||||
and self:follow_holding(self.following) == false then
|
and (self:follow_holding(self.following) == false
|
||||||
|
or self.horny) then
|
||||||
self.following = nil
|
self.following = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2064,6 +2119,15 @@ function mob_class:follow_flop()
|
|||||||
if not self:attempt_flight_correction() then
|
if not self:attempt_flight_correction() then
|
||||||
|
|
||||||
self.state = "flop"
|
self.state = "flop"
|
||||||
|
|
||||||
|
-- do we have a custom on_flop function?
|
||||||
|
if self.on_flop then
|
||||||
|
|
||||||
|
if self:on_flop(self) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
self.object:set_velocity({x = 0, y = -5, z = 0})
|
self.object:set_velocity({x = 0, y = -5, z = 0})
|
||||||
|
|
||||||
self:set_animation("stand")
|
self:set_animation("stand")
|
||||||
@ -3011,6 +3075,7 @@ function mob_class:mob_staticdata()
|
|||||||
if t ~= "function"
|
if t ~= "function"
|
||||||
and t ~= "nil"
|
and t ~= "nil"
|
||||||
and t ~= "userdata"
|
and t ~= "userdata"
|
||||||
|
and _ ~= "object"
|
||||||
and _ ~= "_cmi_components" then
|
and _ ~= "_cmi_components" then
|
||||||
tmp[_] = self[_]
|
tmp[_] = self[_]
|
||||||
end
|
end
|
||||||
@ -3263,6 +3328,8 @@ function mob_class:on_step(dtime, moveresult)
|
|||||||
}}
|
}}
|
||||||
}]]
|
}]]
|
||||||
|
|
||||||
|
if self.state == "die" then return end ----------------
|
||||||
|
|
||||||
if use_cmi then
|
if use_cmi then
|
||||||
cmi.notify_step(self.object, dtime)
|
cmi.notify_step(self.object, dtime)
|
||||||
end
|
end
|
||||||
@ -3462,6 +3529,7 @@ minetest.register_entity(name, setmetatable({
|
|||||||
owner = def.owner,
|
owner = def.owner,
|
||||||
order = def.order,
|
order = def.order,
|
||||||
on_die = def.on_die,
|
on_die = def.on_die,
|
||||||
|
on_flop = def.on_flop,
|
||||||
do_custom = def.do_custom,
|
do_custom = def.do_custom,
|
||||||
jump_height = def.jump_height,
|
jump_height = def.jump_height,
|
||||||
drawtype = def.drawtype, -- DEPRECATED, use rotate instead
|
drawtype = def.drawtype, -- DEPRECATED, use rotate instead
|
||||||
@ -3485,6 +3553,7 @@ minetest.register_entity(name, setmetatable({
|
|||||||
light_damage_max = def.light_damage_max,
|
light_damage_max = def.light_damage_max,
|
||||||
water_damage = def.water_damage,
|
water_damage = def.water_damage,
|
||||||
lava_damage = def.lava_damage,
|
lava_damage = def.lava_damage,
|
||||||
|
air_damage = def.air_damage,
|
||||||
suffocation = def.suffocation,
|
suffocation = def.suffocation,
|
||||||
fall_damage = def.fall_damage,
|
fall_damage = def.fall_damage,
|
||||||
fall_speed = def.fall_speed,
|
fall_speed = def.fall_speed,
|
||||||
@ -3636,9 +3705,6 @@ local can_spawn = function(pos, name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- spawn mob 1/2 node above ground
|
|
||||||
pos.y = pos.y + 0.5
|
|
||||||
|
|
||||||
-- tweak X/Z spawn pos
|
-- tweak X/Z spawn pos
|
||||||
if width_x % 2 == 0 then
|
if width_x % 2 == 0 then
|
||||||
pos.x = pos.x + 0.5
|
pos.x = pos.x + 0.5
|
||||||
@ -3903,11 +3969,33 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
end
|
end
|
||||||
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 height = max(0, ent.collisionbox[5] - ent.collisionbox[2])
|
||||||
|
|
||||||
|
for n = 0, floor(height) do
|
||||||
|
|
||||||
|
local pos2 = {x = pos.x, y = pos.y + n, z = pos.z}
|
||||||
|
|
||||||
|
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
|
||||||
|
--print ("--- inside block", name, node_ok(pos2).name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
-- returns position if we have enough space to spawn mob
|
-- returns position if we have enough space to spawn mob
|
||||||
pos = can_spawn(pos, name)
|
pos = can_spawn(pos, name)
|
||||||
|
end
|
||||||
|
|
||||||
if pos then
|
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)
|
local mob = minetest.add_entity(pos, name)
|
||||||
|
|
||||||
-- print("[mobs] Spawned " .. name .. " at "
|
-- print("[mobs] Spawned " .. name .. " at "
|
||||||
@ -4439,10 +4527,10 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net,
|
|||||||
minetest.add_item(clicker:get_pos(), new_stack)
|
minetest.add_item(clicker:get_pos(), new_stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
remove_mob(self, true)
|
|
||||||
|
|
||||||
self:mob_sound("default_place_node_hard")
|
self:mob_sound("default_place_node_hard")
|
||||||
|
|
||||||
|
remove_mob(self, true)
|
||||||
|
|
||||||
return new_stack
|
return new_stack
|
||||||
|
|
||||||
-- when chance above fails or set to 0, miss!
|
-- when chance above fails or set to 0, miss!
|
||||||
@ -4547,8 +4635,11 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
|||||||
-- make children grow quicker
|
-- make children grow quicker
|
||||||
if self.child == true then
|
if self.child == true then
|
||||||
|
|
||||||
self.hornytimer = self.hornytimer + 20
|
-- self.hornytimer = self.hornytimer + 20
|
||||||
|
-- deduct 10% of the time to adulthood
|
||||||
|
self.hornytimer = self.hornytimer + (
|
||||||
|
(CHILD_GROW_TIME - self.hornytimer) * 0.1)
|
||||||
|
print ("====", self.hornytimer)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
16
api.txt
16
api.txt
@ -64,6 +64,7 @@ functions needed for the mob to work properly which contains the following:
|
|||||||
'fall_damage' when true causes falling to inflict damage.
|
'fall_damage' when true causes falling to inflict damage.
|
||||||
'water_damage' holds the damage per second infliced to mobs when standing in
|
'water_damage' holds the damage per second infliced to mobs when standing in
|
||||||
water.
|
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
|
'lava_damage' holds the damage per second inflicted to mobs when standing
|
||||||
in lava or fire or an ignition source.
|
in lava or fire or an ignition source.
|
||||||
'light_damage' holds the damage per second inflicted to mobs when light
|
'light_damage' holds the damage per second inflicted to mobs when light
|
||||||
@ -226,6 +227,7 @@ functions needed for the mob to work properly which contains the following:
|
|||||||
'die_end'
|
'die_end'
|
||||||
'die_speed'
|
'die_speed'
|
||||||
'die_loop' when set to false stops the animation looping.
|
'die_loop' when set to false stops the animation looping.
|
||||||
|
'die_rotate' if true mob spins during death animation.
|
||||||
|
|
||||||
Using '_loop = false' setting will stop any of the above animations from
|
Using '_loop = false' setting will stop any of the above animations from
|
||||||
looping.
|
looping.
|
||||||
@ -298,6 +300,9 @@ enhance mob functionality and have them do many interesting things:
|
|||||||
is returned normal attack function continued.
|
is returned normal attack function continued.
|
||||||
'on_die' a function that is called when mob is killed (self, pos), also
|
'on_die' a function that is called when mob is killed (self, pos), also
|
||||||
has access to self.cause_of_death table.
|
has access to self.cause_of_death table.
|
||||||
|
'on_flop' function called when flying or swimmimng mob is no longer in
|
||||||
|
air/water, (self) paramater and return true to skip the built
|
||||||
|
in api flop feature.
|
||||||
'do_custom' a custom function that is called every tick while mob is
|
'do_custom' a custom function that is called every tick while mob is
|
||||||
active and which has access to all of the self.* variables
|
active and which has access to all of the self.* variables
|
||||||
e.g. (self.health for health or self.standing_in for node
|
e.g. (self.health for health or self.standing_in for node
|
||||||
@ -329,6 +334,14 @@ for each mob.
|
|||||||
'self.order' set to "follow" or "stand" so that npc will follow owner
|
'self.order' set to "follow" or "stand" so that npc will follow owner
|
||||||
or stand it's ground
|
or stand it's ground
|
||||||
'self.nametag' contains the name of the mob which it can show above
|
'self.nametag' contains the name of the mob which it can show above
|
||||||
|
'self.state' Current mob state.
|
||||||
|
"stand": no movement (except turning around)
|
||||||
|
"walk": walk or move around aimlessly
|
||||||
|
"attack": chase and attack enemy
|
||||||
|
"runaway": flee from target
|
||||||
|
"flop": bounce around aimlessly
|
||||||
|
(for swimming mobs that have stranded)
|
||||||
|
"die": during death
|
||||||
|
|
||||||
|
|
||||||
Adding Mobs in World
|
Adding Mobs in World
|
||||||
@ -697,6 +710,9 @@ External Settings for "minetest.conf"
|
|||||||
function.
|
function.
|
||||||
'mob_nospawn_range' Minimum range a mob can spawn near player (def: 12)
|
'mob_nospawn_range' Minimum range a mob can spawn near player (def: 12)
|
||||||
'mob_active_limit' Number of active mobs in game, 0 for unlimited
|
'mob_active_limit' Number of active mobs in game, 0 for unlimited
|
||||||
|
'mob_area_spawn' When true will check surrounding area the size of the
|
||||||
|
mob for obstructions before spawning, otherwise it
|
||||||
|
defaults to checking the height of the mob only.
|
||||||
|
|
||||||
Players can override the spawn chance for each mob registered by adding a line
|
Players can override the spawn chance for each mob registered by adding a line
|
||||||
to their minetest.conf file with a new value, the lower the value the more each
|
to their minetest.conf file with a new value, the lower the value the more each
|
||||||
|
@ -5,7 +5,7 @@ local S = mobs.intllib
|
|||||||
minetest.register_craftitem("mobs:nametag", {
|
minetest.register_craftitem("mobs:nametag", {
|
||||||
description = S("Name Tag"),
|
description = S("Name Tag"),
|
||||||
inventory_image = "mobs_nametag.png",
|
inventory_image = "mobs_nametag.png",
|
||||||
groups = {flammable = 2}
|
groups = {flammable = 2, nametag = 1}
|
||||||
})
|
})
|
||||||
|
|
||||||
if minetest.get_modpath("dye") and minetest.get_modpath("farming") then
|
if minetest.get_modpath("dye") and minetest.get_modpath("farming") then
|
||||||
@ -20,7 +20,7 @@ end
|
|||||||
minetest.register_craftitem("mobs:leather", {
|
minetest.register_craftitem("mobs:leather", {
|
||||||
description = S("Leather"),
|
description = S("Leather"),
|
||||||
inventory_image = "mobs_leather.png",
|
inventory_image = "mobs_leather.png",
|
||||||
groups = {flammable = 2}
|
groups = {flammable = 2, leather = 1}
|
||||||
})
|
})
|
||||||
|
|
||||||
-- raw meat
|
-- raw meat
|
||||||
@ -119,7 +119,7 @@ minetest.register_craft({
|
|||||||
minetest.register_craftitem("mobs:saddle", {
|
minetest.register_craftitem("mobs:saddle", {
|
||||||
description = S("Saddle"),
|
description = S("Saddle"),
|
||||||
inventory_image = "mobs_saddle.png",
|
inventory_image = "mobs_saddle.png",
|
||||||
groups = {flammable = 2}
|
groups = {flammable = 2, saddle = 1}
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
6
init.lua
6
init.lua
@ -1,6 +1,12 @@
|
|||||||
|
|
||||||
local path = minetest.get_modpath("mobs")
|
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
|
-- Mob API
|
||||||
dofile(path .. "/api.lua")
|
dofile(path .. "/api.lua")
|
||||||
|
|
||||||
|
3
mod.conf
3
mod.conf
@ -1 +1,4 @@
|
|||||||
name = mobs
|
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.
|
||||||
|
193
mount.lua
193
mount.lua
@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
-- lib_mount by Blert2112 (edited by TenPlus1)
|
-- lib_mount by Blert2112 (edited by TenPlus1)
|
||||||
|
|
||||||
local enable_crash = false
|
local abs, cos, floor, sin, sqrt, pi =
|
||||||
local crash_threshold = 6.5 -- ignored if enable_crash=false
|
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)
|
local node_ok = function(pos, fallback)
|
||||||
|
|
||||||
fallback = fallback or mobs.fallback_node
|
fallback = fallback or mobs.fallback_node
|
||||||
|
|
||||||
local node = minetest.get_node_or_nil(pos)
|
local node = minetest.get_node_or_nil(pos)
|
||||||
@ -25,7 +22,6 @@ end
|
|||||||
|
|
||||||
|
|
||||||
local function node_is(pos)
|
local function node_is(pos)
|
||||||
|
|
||||||
local node = node_ok(pos)
|
local node = node_ok(pos)
|
||||||
|
|
||||||
if node.name == "air" then
|
if node.name == "air" then
|
||||||
@ -49,33 +45,30 @@ end
|
|||||||
|
|
||||||
|
|
||||||
local function get_sign(i)
|
local function get_sign(i)
|
||||||
|
|
||||||
i = i or 0
|
i = i or 0
|
||||||
|
|
||||||
if i == 0 then
|
if i == 0 then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return i / math.abs(i)
|
return i / abs(i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function get_velocity(v, yaw, y)
|
local function get_velocity(v, yaw, y)
|
||||||
|
local x = -sin(yaw) * v
|
||||||
local x = -math.sin(yaw) * v
|
local z = cos(yaw) * v
|
||||||
local z = math.cos(yaw) * v
|
|
||||||
|
|
||||||
return {x = x, y = y, z = z}
|
return {x = x, y = y, z = z}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function get_v(v)
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
local function force_detach(player)
|
local function force_detach(player)
|
||||||
|
|
||||||
local attached_to = player:get_attach()
|
local attached_to = player:get_attach()
|
||||||
|
|
||||||
if not attached_to then
|
if not attached_to then
|
||||||
@ -86,21 +79,19 @@ local function force_detach(player)
|
|||||||
|
|
||||||
if entity and entity.driver
|
if entity and entity.driver
|
||||||
and entity.driver == player then
|
and entity.driver == player then
|
||||||
|
|
||||||
entity.driver = nil
|
entity.driver = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
player:set_detach()
|
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})
|
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
||||||
default.player_set_animation(player, "stand" , 30)
|
player_api.set_animation(player, "stand", 30)
|
||||||
player:set_properties({visual_size = {x = 1, y = 1} })
|
player:set_properties({visual_size = {x = 1, y = 1}})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
minetest.register_on_leaveplayer(function(player)
|
minetest.register_on_leaveplayer(function(player)
|
||||||
force_detach(player)
|
force_detach(player)
|
||||||
end)
|
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)
|
function mobs.attach(entity, player)
|
||||||
|
|
||||||
local attach_at, eye_offset = {}, {}
|
|
||||||
|
|
||||||
entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0}
|
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_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}
|
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
|
local rot_view = 0
|
||||||
|
|
||||||
if entity.player_rotation.y == 90 then
|
if entity.player_rotation.y == 90 then
|
||||||
rot_view = math.pi / 2
|
rot_view = pi / 2
|
||||||
end
|
end
|
||||||
|
|
||||||
attach_at = entity.driver_attach_at
|
local attach_at = entity.driver_attach_at
|
||||||
eye_offset = entity.driver_eye_offset
|
local eye_offset = entity.driver_eye_offset
|
||||||
entity.driver = player
|
entity.driver = player
|
||||||
|
|
||||||
force_detach(player)
|
force_detach(player)
|
||||||
|
|
||||||
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
|
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_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
|
||||||
|
|
||||||
player:set_properties({
|
player:set_properties({
|
||||||
@ -151,46 +169,36 @@ function mobs.attach(entity, player)
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.after(0.2, function(name)
|
minetest.after(0.2, function()
|
||||||
local player = minetest.get_player_by_name(name)
|
if player and player:is_player() then
|
||||||
if player then
|
player_api.set_animation(player, "sit", 30)
|
||||||
default.player_set_animation(player, "sit" , 30)
|
|
||||||
end
|
end
|
||||||
end, player:get_player_name())
|
end)
|
||||||
|
|
||||||
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mobs.detach(player, offset)
|
function mobs.detach(player)
|
||||||
|
|
||||||
force_detach(player)
|
force_detach(player)
|
||||||
|
|
||||||
default.player_set_animation(player, "stand" , 30)
|
minetest.after(0.1, function()
|
||||||
|
if player and player:is_player() then
|
||||||
local pos = player:get_pos()
|
local pos = find_free_pos(player:get_pos())
|
||||||
|
pos.y = pos.y + 0.5
|
||||||
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
|
|
||||||
player:set_pos(pos)
|
player:set_pos(pos)
|
||||||
end
|
end
|
||||||
end, player:get_player_name(), pos)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
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
|
if entity.player_rotation.y == 90 then
|
||||||
rot_steer, rot_view = 0, math.pi/2
|
rot_view = pi / 2
|
||||||
end
|
end
|
||||||
|
|
||||||
local acce_y = 0
|
local acce_y = 0
|
||||||
@ -200,19 +208,14 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
|
|
||||||
-- process controls
|
-- process controls
|
||||||
if entity.driver then
|
if entity.driver then
|
||||||
|
|
||||||
--print ("---velo", get_v(velo))
|
|
||||||
|
|
||||||
local ctrl = entity.driver:get_player_control()
|
local ctrl = entity.driver:get_player_control()
|
||||||
|
|
||||||
-- move forwards
|
-- move forwards
|
||||||
if ctrl.up then
|
if ctrl.up then
|
||||||
|
|
||||||
entity.v = entity.v + entity.accel / 10
|
entity.v = entity.v + entity.accel / 10
|
||||||
|
|
||||||
-- move backwards
|
-- move backwards
|
||||||
elseif ctrl.down then
|
elseif ctrl.down then
|
||||||
|
|
||||||
if entity.max_speed_reverse == 0 and entity.v == 0 then
|
if entity.max_speed_reverse == 0 and entity.v == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -220,12 +223,24 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
entity.v = entity.v - entity.accel / 10
|
entity.v = entity.v - entity.accel / 10
|
||||||
end
|
end
|
||||||
|
|
||||||
-- fix mob rotation
|
-- mob rotation
|
||||||
local horz = entity.driver:get_look_horizontal() or 0
|
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)
|
entity.object:set_yaw(horz - entity.rotate)
|
||||||
|
|
||||||
if can_fly then
|
if can_fly then
|
||||||
|
|
||||||
-- fly up
|
-- fly up
|
||||||
if ctrl.jump then
|
if ctrl.jump then
|
||||||
velo.y = velo.y + 1
|
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
|
velo.y = velo.y + 0.1
|
||||||
if velo.y > 0 then velo.y = 0 end
|
if velo.y > 0 then velo.y = 0 end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- jump
|
-- jump
|
||||||
if ctrl.jump then
|
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 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 entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
||||||
|
|
||||||
if stand_anim then
|
if stand_anim then
|
||||||
mobs:set_animation(entity, stand_anim)
|
mobs:set_animation(entity, stand_anim)
|
||||||
end
|
end
|
||||||
@ -280,7 +292,6 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
entity.v = entity.v - 0.02 * s
|
entity.v = entity.v - 0.02 * s
|
||||||
|
|
||||||
if s ~= get_sign(entity.v) then
|
if s ~= get_sign(entity.v) then
|
||||||
|
|
||||||
entity.object:set_velocity({x = 0, y = 0, z = 0})
|
entity.object:set_velocity({x = 0, y = 0, z = 0})
|
||||||
entity.v = 0
|
entity.v = 0
|
||||||
return
|
return
|
||||||
@ -293,14 +304,15 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
max_spd = entity.max_speed_forward
|
max_spd = entity.max_speed_forward
|
||||||
end
|
end
|
||||||
|
|
||||||
if math.abs(entity.v) > max_spd then
|
if abs(entity.v) > max_spd then
|
||||||
entity.v = entity.v - get_sign(entity.v)
|
entity.v = entity.v - get_sign(entity.v)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set position, velocity and acceleration
|
-- Set position, velocity and acceleration
|
||||||
local p = entity.object:get_pos()
|
local p = entity.object:get_pos()
|
||||||
local new_velo
|
if not p then return end
|
||||||
local new_acce = {x = 0, y = -9.8, z = 0}
|
|
||||||
|
local new_acce = {x = 0, y = -9.81, z = 0}
|
||||||
|
|
||||||
p.y = p.y - 0.5
|
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
|
local v = entity.v
|
||||||
|
|
||||||
if ni == "air" then
|
if ni == "air" then
|
||||||
|
|
||||||
if can_fly == true then
|
if can_fly == true then
|
||||||
new_acce.y = 0
|
new_acce.y = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif ni == "liquid" or ni == "lava" then
|
elseif ni == "liquid" or ni == "lava" then
|
||||||
|
|
||||||
if ni == "lava" and entity.lava_damage ~= 0 then
|
if ni == "lava" and entity.lava_damage ~= 0 then
|
||||||
|
|
||||||
entity.lava_counter = (entity.lava_counter or 0) + dtime
|
entity.lava_counter = (entity.lava_counter or 0) + dtime
|
||||||
|
|
||||||
if entity.lava_counter > 1 then
|
if entity.lava_counter > 1 then
|
||||||
|
|
||||||
minetest.sound_play("default_punch", {
|
minetest.sound_play("default_punch", {
|
||||||
object = entity.object,
|
object = entity.object,
|
||||||
max_hear_distance = 5
|
max_hear_distance = 5
|
||||||
}, true)
|
})
|
||||||
|
|
||||||
entity.object:punch(entity.object, 1.0, {
|
entity.object:punch(entity.object, 1.0, {
|
||||||
full_punch_interval = 1.0,
|
full_punch_interval = 1.0,
|
||||||
@ -335,14 +342,12 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if entity.terrain_type == 2
|
local terrain_type = entity.terrain_type
|
||||||
or entity.terrain_type == 3 then
|
if terrain_type == 2 or terrain_type == 3 then
|
||||||
|
|
||||||
new_acce.y = 0
|
new_acce.y = 0
|
||||||
p.y = p.y + 1
|
p.y = p.y + 1
|
||||||
|
|
||||||
if node_is(p) == "liquid" then
|
if node_is(p) == "liquid" then
|
||||||
|
|
||||||
if velo.y >= 5 then
|
if velo.y >= 5 then
|
||||||
velo.y = 5
|
velo.y = 5
|
||||||
elseif velo.y < 0 then
|
elseif velo.y < 0 then
|
||||||
@ -351,9 +356,11 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
new_acce.y = 5
|
new_acce.y = 5
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if math.abs(velo.y) < 1 then
|
if abs(velo.y) < 1 then
|
||||||
local pos = entity.object:get_pos()
|
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)
|
entity.object:set_pos(pos)
|
||||||
velo.y = 0
|
velo.y = 0
|
||||||
end
|
end
|
||||||
@ -363,46 +370,22 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||||||
end
|
end
|
||||||
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
|
new_acce.y = new_acce.y + acce_y
|
||||||
|
|
||||||
entity.object:set_velocity(new_velo)
|
entity.object:set_velocity(new_velo)
|
||||||
entity.object:set_acceleration(new_acce)
|
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
|
entity.v2 = v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- directional flying routine by D00Med (edited by TenPlus1)
|
-- directional flying routine by D00Med (edited by TenPlus1)
|
||||||
|
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
|
||||||
function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
|
|
||||||
|
|
||||||
local ctrl = entity.driver:get_player_control()
|
local ctrl = entity.driver:get_player_control()
|
||||||
local velo = entity.object:get_velocity()
|
local velo = entity.object:get_velocity()
|
||||||
local dir = entity.driver:get_look_dir()
|
local dir = entity.driver:get_look_dir()
|
||||||
local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
|
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
|
if ctrl.up then
|
||||||
entity.object:set_velocity({
|
entity.object:set_velocity({
|
||||||
@ -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})
|
entity.object:set_velocity({x = 0, y = -2, z = 0})
|
||||||
end
|
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
|
-- firing arrows
|
||||||
if ctrl.LMB and ctrl.sneak and shoots then
|
if ctrl.LMB and ctrl.sneak and shoots then
|
||||||
|
|
||||||
local pos = entity.object:get_pos()
|
local pos = entity.object:get_pos()
|
||||||
local obj = minetest.add_entity({
|
local obj = minetest.add_entity({
|
||||||
x = pos.x + 0 + dir.x * 2.5,
|
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.switch = 1 -- for mob specific arrows
|
||||||
ent.owner_id = tostring(entity.object) -- so arrows dont hurt entity you are riding
|
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 vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
|
||||||
local yaw = entity.driver:get_look_horizontal()
|
yaw = entity.driver:get_look_horizontal()
|
||||||
obj:set_yaw(yaw + math.pi / 2)
|
obj:set_yaw(yaw + pi / 2)
|
||||||
obj:set_velocity(vec)
|
obj:set_velocity(vec)
|
||||||
else
|
else
|
||||||
obj:remove()
|
obj:remove()
|
||||||
@ -448,7 +430,6 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
|
|||||||
|
|
||||||
-- change animation if stopped
|
-- change animation if stopped
|
||||||
if velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
if velo.x == 0 and velo.y == 0 and velo.z == 0 then
|
||||||
|
|
||||||
mobs:set_animation(entity, stand_anim)
|
mobs:set_animation(entity, stand_anim)
|
||||||
else
|
else
|
||||||
-- moving animation
|
-- moving animation
|
||||||
|
@ -23,6 +23,8 @@ Lucky Blocks: 9
|
|||||||
|
|
||||||
|
|
||||||
Changelog:
|
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.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,
|
- 1.52 - Added 'mob_active_limit' in settings to set number of mobs in game,
|
||||||
(default is 0 for unlimited), removed {immortal} from mob armor, fluid viscocity slows mobs
|
(default is 0 for unlimited), removed {immortal} from mob armor, fluid viscocity slows mobs
|
||||||
|
@ -33,3 +33,9 @@ mob_nospawn_range (Mob no-spawn range) float 12.0
|
|||||||
|
|
||||||
# Sets maximum number of active mobs in game (0 for unlimited)
|
# Sets maximum number of active mobs in game (0 for unlimited)
|
||||||
mob_active_limit (Mob Active Limit) float 0
|
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
|
||||||
|
13
spawner.lua
13
spawner.lua
@ -23,9 +23,9 @@ minetest.register_node("mobs:spawner", {
|
|||||||
|
|
||||||
-- text entry formspec
|
-- text entry formspec
|
||||||
meta:set_string("formspec",
|
meta:set_string("formspec",
|
||||||
"size[9,3.5]"
|
"size[10,3.5]"
|
||||||
.. "label[0.15,0.5;" .. minetest.formspec_escape(head) .. "]"
|
.. "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}]")
|
.. ";${command}]")
|
||||||
|
|
||||||
meta:set_string("infotext", S("Spawner Not Active (enter settings)"))
|
meta:set_string("infotext", S("Spawner Not Active (enter settings)"))
|
||||||
@ -162,10 +162,17 @@ minetest.register_abm({
|
|||||||
end
|
end
|
||||||
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
|
-- find air blocks within 5 nodes of spawner
|
||||||
local air = minetest.find_nodes_in_area(
|
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},
|
||||||
{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
|
-- spawn in random air block
|
||||||
if air and #air > 0 then
|
if air and #air > 0 then
|
||||||
|
Reference in New Issue
Block a user