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

Compare commits

...

7 Commits

4 changed files with 196 additions and 87 deletions

256
api.lua
View File

@ -8,7 +8,7 @@ local use_cmi = minetest.global_exists("cmi")
mobs = {
mod = "redo",
version = "20201003",
version = "20201206",
intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {}
}
@ -58,6 +58,7 @@ local mobs_drop_items = settings:get_bool("mobs_drop_items") ~= false
local mobs_griefing = settings:get_bool("mobs_griefing") ~= false
local spawn_protected = settings:get_bool("mobs_spawn_protected") ~= 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 show_health = settings:get_bool("mob_show_health") ~= false
local max_per_block = tonumber(settings:get("max_objects_per_block") or 99)
@ -111,6 +112,7 @@ local mob_class = {
light_damage_max = 15,
water_damage = 0,
lava_damage = 0,
air_damage = 0,
suffocation = 2,
fall_damage = 1,
fall_speed = -10, -- must be lower than -2 (default: -10)
@ -276,10 +278,10 @@ function mob_class:set_velocity(v)
c_x, c_y = unpack(self:collision())
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
v = v or 0
v = v or 0.01
-- check if standing in liquid with max viscosity of 7
local visc = min(minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
@ -291,8 +293,8 @@ function mob_class:set_velocity(v)
v = v / (visc + 1)
end
-- set velocity with hard limit of 10
local vel = self.object:get_velocity()
-- set velocity
local vel = self.object:get_velocity() or 0
local new_vel = {
x = (sin(yaw) * -v) + c_x,
@ -828,6 +830,11 @@ end
-- check if mob is dead or only hurt
function mob_class:check_for_death(cmi_cause)
-- We dead already
if self.state == "die" then
return true
end
-- has health actually changed?
if self.health == self.old_health and self.health > 0 then
return false
@ -877,7 +884,7 @@ function mob_class:check_for_death(cmi_cause)
local pos = self.object:get_pos()
-- execute custom death function
if self.on_die then
if pos and self.on_die then
self:on_die(pos)
@ -897,7 +904,8 @@ function mob_class:check_for_death(cmi_cause)
local frames = self.animation.die_end - self.animation.die_start
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.v_start = false
@ -905,28 +913,37 @@ function mob_class:check_for_death(cmi_cause)
self.blinktimer = 0
self.passive = true
self.state = "die"
self.object:set_properties({
pointable = false, collide_with_objects = false,
automatic_rotate = rot,
})
self:set_velocity(0)
self:set_animation("die")
minetest.after(length, function(self)
if use_cmi and self.object:get_luaentity() then
cmi.notify_die(self.object, cmi_cause)
if self.object:get_luaentity() then
if use_cmi then
cmi.notify_die(self.object, cmi_cause)
end
remove_mob(self, true)
end
remove_mob(self, true)
end, self)
else
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)
end
effect(pos, 20, "tnt_smoke.png")
effect(pos, 20, "tnt_smoke.png")
end
return true
end
@ -1084,6 +1101,19 @@ function mob_class:do_env_damage()
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
if self.light_damage ~= 0 then
@ -1290,16 +1320,20 @@ function mob_class:follow_holding(clicker)
return false
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
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
self.hornytimer = self.hornytimer + 1
if self.hornytimer > 240 then
if self.hornytimer > CHILD_GROW_TIME then
self.child = false
self.hornytimer = 0
@ -1328,14 +1362,14 @@ function mob_class:breed()
return
end
-- horny animal can mate for 40 seconds,
-- afterwards horny animal cannot mate again for 200 seconds
-- horny animal can mate for HORNY_TIME seconds,
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
if self.horny == true
and self.hornytimer < 240 then
and self.hornytimer < HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = self.hornytimer + 1
if self.hornytimer >= 240 then
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = 0
self.horny = false
end
@ -1343,7 +1377,7 @@ function mob_class:breed()
-- find another same animal who is also horny and mate if nearby
if self.horny == true
and self.hornytimer <= 40 then
and self.hornytimer <= HORNY_TIME then
local pos = self.object:get_pos()
@ -1351,7 +1385,6 @@ function mob_class:breed()
"heart.png", 3, 4, 1, 0.1)
local objs = minetest.get_objects_inside_radius(pos, 3)
local num = 0
local ent
for n = 1, #objs do
@ -1380,18 +1413,20 @@ function mob_class:breed()
end
end
if ent
-- found another similar horny animal that isn't self?
if ent and ent.object ~= self.object
and canmate == true
and ent.horny == true
and ent.hornytimer <= 40 then
num = num + 1
end
and ent.hornytimer <= HORNY_TIME then
-- found your mate? then have a baby
if num > 1 then
local pos2 = ent.object:get_pos()
self.hornytimer = 41
ent.hornytimer = 41
-- Have mobs face one another
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
if active_limit > 0 and active_mobs >= active_limit then
@ -1459,8 +1494,6 @@ function mob_class:breed()
ent2.owner = self.owner
end, self, ent)
num = 0
break
end
end
@ -2005,10 +2038,11 @@ function mob_class:follow_flop()
self.following = nil
end
else
-- stop following player if not holding specific item
-- stop following player if not holding specific item or mob is horny
if self.following
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
end
@ -2064,6 +2098,15 @@ function mob_class:follow_flop()
if not self:attempt_flight_correction() then
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:set_animation("stand")
@ -3462,6 +3505,7 @@ minetest.register_entity(name, setmetatable({
owner = def.owner,
order = def.order,
on_die = def.on_die,
on_flop = def.on_flop,
do_custom = def.do_custom,
jump_height = def.jump_height,
drawtype = def.drawtype, -- DEPRECATED, use rotate instead
@ -3485,6 +3529,7 @@ minetest.register_entity(name, setmetatable({
light_damage_max = def.light_damage_max,
water_damage = def.water_damage,
lava_damage = def.lava_damage,
air_damage = def.air_damage,
suffocation = def.suffocation,
fall_damage = def.fall_damage,
fall_speed = def.fall_speed,
@ -3594,6 +3639,68 @@ local count_mobs = function(pos, type)
end
-- do we have enough space to spawn mob? (thanks wuzzy)
local can_spawn = function(pos, name)
local ent = minetest.registered_entities[name]
local width_x = max(1, ceil(ent.collisionbox[4] - ent.collisionbox[1]))
local min_x, max_x
if width_x % 2 == 0 then
max_x = floor(width_x / 2)
min_x = -(max_x - 1)
else
max_x = floor(width_x / 2)
min_x = -max_x
end
local width_z = max(1, ceil(ent.collisionbox[6] - ent.collisionbox[3]))
local min_z, max_z
if width_z % 2 == 0 then
max_z = floor(width_z / 2)
min_z = -(max_z - 1)
else
max_z = floor(width_z / 2)
min_z = -max_z
end
local max_y = max(0, ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1)
local pos2
for y = 0, max_y do
for x = min_x, max_x do
for z = min_z, max_z do
pos2 = {x = pos.x + x, y = pos.y + y, z = pos.z + z}
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
return nil
end
end
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
end
if width_z % 2 == 0 then
pos.z = pos.z + 0.5
end
return pos
end
function mobs:can_spawn(pos, name)
return can_spawn(pos, name)
end
-- global functions
function mobs:add_mob(pos, def)
@ -3841,69 +3948,41 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
end
end
-- do we have enough space to spawn mob? (thanks wuzzy)
local ent = minetest.registered_entities[name]
local width_x = max(1, ceil(ent.collisionbox[4] - ent.collisionbox[1]))
local min_x, max_x
-- should we check mob area for obstructions ?
if mob_area_spawn ~= true then
if width_x % 2 == 0 then
max_x = floor(width_x / 2)
min_x = -(max_x - 1)
else
max_x = floor(width_x / 2)
min_x = -max_x
end
-- 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 width_z = max(1, ceil(ent.collisionbox[6] - ent.collisionbox[3]))
local min_z, max_z
for n = 0, height do
if width_z % 2 == 0 then
max_z = floor(width_z / 2)
min_z = -(max_z - 1)
else
max_z = floor(width_z / 2)
min_z = -max_z
end
local pos2 = {x = pos.x, y = pos.y + n, z = pos.z}
local max_y = max(0, ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1)
for y = 0, max_y do
for x = min_x, max_x do
for z = min_z, max_z do
local pos2 = {
x = pos.x + x,
y = pos.y + y,
z = pos.z + z}
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
--print("--- not enough space to spawn", name)
return
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
--print ("--- inside block", name, node_ok(pos2).name)
return
end
end
end
end
else
-- returns position if we have enough space to spawn mob
pos = can_spawn(pos, name)
end
-- spawn mob 1/2 node above ground
pos.y = pos.y + 0.5
if pos then
-- tweak X/Z spawn pos
if width_x % 2 == 0 then
pos.x = pos.x + 0.5
end
if width_z % 2 == 0 then
pos.z = pos.z + 0.5
end
local mob = minetest.add_entity(pos, name)
local mob = minetest.add_entity(pos, name)
-- print("[mobs] Spawned " .. name .. " at "
-- .. minetest.pos_to_string(pos) .. " on "
-- .. node.name .. " near " .. neighbors[1])
if on_spawn then
on_spawn(mob:get_luaentity(), pos)
if on_spawn then
on_spawn(mob:get_luaentity(), pos)
end
else
--print("--- not enough space to spawn", name)
end
end
@ -4532,8 +4611,11 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
-- make children grow quicker
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
end

23
api.txt
View File

@ -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.
'water_damage' holds the damage per second infliced to mobs when standing in
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.
'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_speed'
'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
looping.
@ -298,6 +300,9 @@ enhance mob functionality and have them do many interesting things:
is returned normal attack function continued.
'on_die' a function that is called when mob is killed (self, pos), also
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
active and which has access to all of the self.* variables
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
or stand it's ground
'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
@ -660,6 +673,13 @@ Use this instead:
mob_class:line_of_sight(pos1, pos2, stepsize)
mobs:can_spawn(pos, name)
This function checks the surrounding area at [pos] to see if there is enough empty
space to spawn mob [name], if so then a new position is returned for use,
otherwise nil is returned.
External Settings for "minetest.conf"
------------------------------------
@ -690,6 +710,9 @@ External Settings for "minetest.conf"
function.
'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_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
to their minetest.conf file with a new value, the lower the value the more each

View File

@ -23,6 +23,7 @@ Lucky Blocks: 9
Changelog:
- 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,
(default is 0 for unlimited), removed {immortal} from mob armor, fluid viscocity slows mobs

View File

@ -33,3 +33,6 @@ mob_nospawn_range (Mob no-spawn range) float 12.0
# Sets maximum number of active mobs in game (0 for unlimited)
mob_active_limit (Mob Active Limit) float 0
# Enables area check when spawning mobs
mob_area_spawn (Mob Area Spawn) bool false