1
0
mirror of https://codeberg.org/tenplus1/mobs_redo.git synced 2025-07-27 12:30:18 +02:00

Compare commits

...

11 Commits

6 changed files with 268 additions and 99 deletions

299
api.lua
View File

@ -6,7 +6,7 @@ local use_cmi = minetest.global_exists("cmi")
mobs = { mobs = {
mod = "redo", mod = "redo",
version = "20200619", version = "20200701",
intllib = S, intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {} invis = minetest.global_exists("invisibility") and invisibility or {}
} }
@ -206,7 +206,6 @@ end
function mob_class:collision() function mob_class:collision()
local pos = self.object:get_pos() local pos = self.object:get_pos()
local vel = self.object:get_velocity()
local x, z = 0, 0 local x, z = 0, 0
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5 local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
@ -229,12 +228,36 @@ function mob_class:collision()
end end
-- check string against another string or table
local check_for = function(look_for, look_inside)
if type(look_inside) == "string" and look_inside == look_for then
return true
elseif type(look_inside) == "table" then
for _, str in pairs(look_inside) do
if str == look_for then
return true
end
end
end
return false
end
-- move mob in facing direction -- move mob in facing direction
function mob_class:set_velocity(v) function mob_class:set_velocity(v)
-- halt mob if it has been ordered to stay -- halt mob if it has been ordered to stay
if self.order == "stand" then if self.order == "stand" then
self.object:set_velocity({x = 0, y = 0, z = 0}) self.object:set_velocity({x = 0, y = 0, z = 0})
return return
end end
@ -250,14 +273,26 @@ function mob_class:set_velocity(v)
-- nil check for velocity -- nil check for velocity
v = v or 0 v = v or 0
-- check if standing in liquid with max viscosity of 7
local visc = min(minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
-- only slow mob trying to move while inside a viscous fluid that
-- they aren't meant to be in (fish in water, spiders in cobweb etc)
if v > 0 and visc and visc > 0
and not check_for(self.standing_in, self.fly_in) then
v = v / (visc + 1)
end
-- set velocity with hard limit of 10 -- set velocity with hard limit of 10
local vel = self.object:get_velocity() local vel = self.object:get_velocity()
self.object:set_velocity({ local new_vel = {
x = max(-10, min((sin(yaw) * -v) + c_x, 10)), x = (sin(yaw) * -v) + c_x,
y = max(-10, min((vel and vel.y or 0), 10)), y = vel.y,
z = max(-10, min((cos(yaw) * v) + c_y, 10)) z = (cos(yaw) * v) + c_y
}) }
self.object:set_velocity(new_vel)
end end
-- global version of above function -- global version of above function
@ -550,20 +585,9 @@ function mob_class:flight_check()
if not def then return false end if not def then return false end
if type(self.fly_in) == "string" -- are we standing inside what we should be to fly/swim ?
and self.standing_in == self.fly_in then if check_for(self.standing_in, self.fly_in) then
return true return true
elseif type(self.fly_in) == "table" then
for _,fly_in in pairs(self.fly_in) do
if self.standing_in == fly_in then
return true
end
end
end end
-- stops mobs getting stuck inside stairs and plantlike nodes -- stops mobs getting stuck inside stairs and plantlike nodes
@ -645,7 +669,14 @@ local effect = function(pos, amount, texture, min_size, max_size,
max_size = max_size or 1 max_size = max_size or 1
gravity = gravity or -10 gravity = gravity or -10
glow = glow or 0 glow = glow or 0
fall = fall and 0 or -radius
if fall == true then
fall = 0
elseif fall == false then
fall = radius
else
fall = -radius
end
minetest.add_particlespawner({ minetest.add_particlespawner({
amount = amount, amount = amount,
@ -665,6 +696,12 @@ local effect = function(pos, amount, texture, min_size, max_size,
}) })
end end
function mobs:effect(pos, amount, texture, min_size, max_size,
radius, gravity, glow, fall)
effect(pos, amount, texture, min_size, max_size, radius, gravity, glow, fall)
end
-- update nametag colour -- update nametag colour
function mob_class:update_tag() function mob_class:update_tag()
@ -1107,14 +1144,8 @@ function mob_class:do_jump()
-- sanity check -- sanity check
if not yaw then return false end if not yaw then return false end
-- what is mob standing on? -- we can only jump if standing on solid node
pos.y = pos.y + self.collisionbox[2] - 0.2 if minetest.registered_nodes[self.standing_on].walkable == false then
local nod = node_ok(pos)
--print("standing on:", nod.name, pos.y)
if minetest.registered_nodes[nod.name].walkable == false then
return false return false
end end
@ -1122,22 +1153,22 @@ function mob_class:do_jump()
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5) local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5) local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
-- set y_pos to base of mob
pos.y = pos.y + self.collisionbox[2]
-- what is in front of mob? -- what is in front of mob?
local nod = node_ok({ local nod = node_ok({
x = pos.x + dir_x, x = pos.x + dir_x, y = pos.y + 0.5, z = pos.z + dir_z
y = pos.y + 0.5,
z = pos.z + dir_z
}) })
-- what is above and in front? -- what is above and in front?
local nodt = node_ok({ local nodt = node_ok({
x = pos.x + dir_x, x = pos.x + dir_x, y = pos.y + 1.5, z = pos.z + dir_z
y = pos.y + 1.5,
z = pos.z + dir_z
}) })
local blocked = minetest.registered_nodes[nodt.name].walkable local blocked = minetest.registered_nodes[nodt.name].walkable
--print("standing on:", self.standing_on, pos.y - 0.25)
--print("in front:", nod.name, pos.y + 0.5) --print("in front:", nod.name, pos.y + 0.5)
--print("in front above:", nodt.name, pos.y + 1.5) --print("in front above:", nodt.name, pos.y + 1.5)
@ -1239,22 +1270,10 @@ function mob_class:follow_holding(clicker)
end end
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
local t = type(self.follow)
-- single item -- are we holding an item mob can follow ?
if t == "string" if check_for(item:get_name(), self.follow) then
and item:get_name() == self.follow then
return true return true
-- multiple items
elseif t == "table" then
for no = 1, #self.follow do
if self.follow[no] == item:get_name() then
return true
end
end
end end
return false return false
@ -1944,8 +1963,8 @@ function mob_class:do_runaway_from()
if name ~= "" and name ~= self.name if name ~= "" and name ~= self.name
and specific_runaway(self.runaway_from, name) then and specific_runaway(self.runaway_from, name) then
p = player:get_pos()
sp = s sp = s
p = player and player:get_pos() or s
-- aim higher to make looking up hills more realistic -- aim higher to make looking up hills more realistic
p.y = p.y + 1 p.y = p.y + 1
@ -2352,10 +2371,10 @@ function mob_class:do_states(dtime)
self.blinktimer = 0 self.blinktimer = 0
if self.blinkstatus then if self.blinkstatus then
-- self.object:set_texture_mod("")
self.object:set_texture_mod(self.texture_mods) self.object:set_texture_mod(self.texture_mods)
else else
-- self.object:set_texture_mod("^[brighten")
self.object:set_texture_mod(self.texture_mods self.object:set_texture_mod(self.texture_mods
.. "^[brighten") .. "^[brighten")
end end
@ -2567,11 +2586,7 @@ function mob_class:do_states(dtime)
p.y = p.y - .5 p.y = p.y - .5
s.y = s.y + .5 s.y = s.y + .5
local vec = { local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
x = p.x - s.x,
y = p.y - s.y,
z = p.z - s.z
}
yaw = yaw_to_pos(self, p) yaw = yaw_to_pos(self, p)
@ -2628,39 +2643,33 @@ function mob_class:falling(pos)
-- sanity check -- sanity check
if not v then return end if not v then return end
if v.y > 0 then local fall_speed = -10 -- gravity
-- apply gravity when moving up -- don't exceed mob fall speed
self.object:set_acceleration({ if v.y < self.fall_speed then
x = 0, fall_speed = self.fall_speed
y = -10,
z = 0
})
elseif v.y <= 0 and v.y > self.fall_speed then
-- fall downwards at set speed
self.object:set_acceleration({
x = 0,
y = self.fall_speed,
z = 0
})
else
-- stop accelerating once max fall speed hit
self.object:set_acceleration({x = 0, y = 0, z = 0})
end end
-- in water then float up -- in water then use liquid viscosity for float/sink speed
if self.standing_in if (self.standing_in
and minetest.registered_nodes[self.standing_in].groups.water then and minetest.registered_nodes[self.standing_in].groups.liquid) --water)
or (self.standing_on
and minetest.registered_nodes[self.standing_in].groups.liquid) then -- water) then
local visc = min(
minetest.registered_nodes[self.standing_in].liquid_viscosity, 7)
if self.floats == 1 then if self.floats == 1 then
self.object:set_acceleration({ -- floating up
x = 0, if visc > 0 then
y = -self.fall_speed / (max(1, v.y) ^ 8), -- 8 was 2 fall_speed = max(1, v.y) / (visc + 1)
z = 0 end
}) else
-- sinking down
if visc > 0 then
fall_speed = -(max(1, v.y) / (visc + 1))
end
end end
else else
@ -2684,6 +2693,13 @@ function mob_class:falling(pos)
self.old_y = self.object:get_pos().y self.old_y = self.object:get_pos().y
end end
end end
-- fall at set speed
self.object:set_acceleration({
x = 0,
y = fall_speed,
z = 0
})
end end
@ -3170,6 +3186,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
self.selectionbox = selbox self.selectionbox = selbox
self.visual_size = vis_size self.visual_size = vis_size
self.standing_in = "air" self.standing_in = "air"
self.standing_on = "air"
-- check existing nametag -- check existing nametag
if not self.nametag then if not self.nametag then
@ -3296,6 +3313,9 @@ function mob_class:on_step(dtime, moveresult)
self.standing_in = node_ok({ self.standing_in = node_ok({
x = pos.x, y = pos.y + y_level + 0.25, z = pos.z}, "air").name x = pos.x, y = pos.y + y_level + 0.25, z = pos.z}, "air").name
self.standing_on = node_ok({
x = pos.x, y = pos.y + y_level - 0.25, z = pos.z}, "air").name
--print("standing in " .. self.standing_in) --print("standing in " .. self.standing_in)
-- if standing inside solid block then jump to escape -- if standing inside solid block then jump to escape
@ -3451,7 +3471,7 @@ mobs.spawning_mobs = {}
-- register mob entity -- register mob entity
function mobs:register_mob(name, def) function mobs:register_mob(name, def)
mobs.spawning_mobs[name] = true mobs.spawning_mobs[name] = {}
minetest.register_entity(name, setmetatable({ minetest.register_entity(name, setmetatable({
@ -3598,6 +3618,106 @@ end
-- global functions -- global functions
function mobs:add_mob(pos, def)
-- is mob actually registered?
if not mobs.spawning_mobs[def.name]
or not minetest.registered_entities[def.name] then
--print("--- mob doesn't exist", def.name)
return
end
-- are we over active mob limit
if active_limit > 0 and active_mobs >= active_limit then
--print("--- active mob limit reached", active_mobs, active_limit)
return
end
-- get total number of this mob in area
local num_mob, is_pla = count_mobs(pos, def.name)
if not is_pla then
--print("--- no players within active area, will not spawn " .. def.name)
return
end
local aoc = mobs.spawning_mobs[def.name]
and mobs.spawning_mobs[def.name].aoc or 1
if def.ignore_count ~= true and num_mob >= aoc then
--print("--- too many " .. def.name .. " in area", num_mob .. "/" .. aoc)
return
end
local mob = minetest.add_entity(pos, def.name)
--print("[mobs] Spawned " .. def.name .. " at " .. minetest.pos_to_string(pos))
local ent = mob:get_luaentity()
if not ent then
--print("[mobs] entity not found " .. def.name)
return false
end
if def.child then
local textures = ent.base_texture
-- using specific child texture (if found)
if ent.child_texture then
textures = ent.child_texture[1]
end
-- and resize to half height
mob:set_properties({
textures = textures,
visual_size = {
x = ent.base_size.x * .5,
y = ent.base_size.y * .5
},
collisionbox = {
ent.base_colbox[1] * .5,
ent.base_colbox[2] * .5,
ent.base_colbox[3] * .5,
ent.base_colbox[4] * .5,
ent.base_colbox[5] * .5,
ent.base_colbox[6] * .5
},
selectionbox = {
ent.base_selbox[1] * .5,
ent.base_selbox[2] * .5,
ent.base_selbox[3] * .5,
ent.base_selbox[4] * .5,
ent.base_selbox[5] * .5,
ent.base_selbox[6] * .5
},
})
ent.child = true
end
if def.owner then
ent.tamed = true
ent.owner = def.owner
end
if def.nametag then
-- limit name entered to 64 characters long
if def.nametag:len() > 64 then
def.nametag = def.nametag:sub(1, 64)
end
ent.nametag = def.nametag
ent:update_tag()
end
return ent
end
function mobs:spawn_abm_check(pos, node, name) function mobs:spawn_abm_check(pos, node, name)
-- global function to add additional spawn checks -- global function to add additional spawn checks
-- return true to stop spawning mob -- return true to stop spawning mob
@ -3608,7 +3728,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
interval, chance, aoc, min_height, max_height, day_toggle, on_spawn) interval, chance, aoc, min_height, max_height, day_toggle, on_spawn)
-- Do mobs spawn at all? -- Do mobs spawn at all?
if not mobs_spawn then if not mobs_spawn or not mobs.spawning_mobs[name] then
return return
end end
@ -3632,6 +3752,8 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
end end
mobs.spawning_mobs[name].aoc = aoc
minetest.register_abm({ minetest.register_abm({
label = name .. " spawning", label = name .. " spawning",
@ -3862,6 +3984,7 @@ function mobs:register_arrow(name, def)
drop = def.drop or false, -- drops arrow as registered item when true drop = def.drop or false, -- drops arrow as registered item when true
collisionbox = def.collisionbox or {-.1, -.1, -.1, .1, .1, .1}, collisionbox = def.collisionbox or {-.1, -.1, -.1, .1, .1, .1},
timer = 0, timer = 0,
lifetime = def.lifetime or 4.5,
switch = 0, switch = 0,
owner_id = def.owner_id, owner_id = def.owner_id,
rotate = def.rotate, rotate = def.rotate,
@ -3876,11 +3999,11 @@ function mobs:register_arrow(name, def)
on_step = def.on_step or function(self, dtime) on_step = def.on_step or function(self, dtime)
self.timer = self.timer + 1 self.timer = self.timer + dtime
local pos = self.object:get_pos() local pos = self.object:get_pos()
if self.switch == 0 or self.timer > 150 then if self.switch == 0 or self.timer > self.lifetime then
self.object:remove() ; -- print("removed arrow") self.object:remove() ; -- print("removed arrow")

39
api.txt
View File

@ -293,7 +293,8 @@ enhance mob functionality and have them do many interesting things:
'custom_attack' when set this function is called instead of the normal mob 'custom_attack' when set this function is called instead of the normal mob
melee attack, parameters are (self, to_attack) and if true melee attack, parameters are (self, to_attack) and if true
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) 'on_die' a function that is called when mob is killed (self, pos), also
has access to self.cause_of_death table.
'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
@ -327,6 +328,20 @@ for each mob.
'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
Adding Mobs in World
--------------------
mobs:add_mob(pos, {
name = "mobs_animal:chicken",
child = true,
owner = "singleplayer",
nametag = "Bessy",
ignore_count = true -- ignores mob count per map area
})
Returns false if mob could not be added, returns mob object if spawned ok.
Spawning Mobs in World Spawning Mobs in World
---------------------- ----------------------
@ -387,6 +402,24 @@ true the mob will not spawn.
'name' is the name of the animal/monster 'name' is the name of the animal/monster
Particle Effects
----------------
mobs:effect(pos, amount, texture, min_size, max_size, radius, gravity, glow, fall)
This function provides a quick way to spawn particles as an effect.
'pos' center position of particle effect.
'amount' how many particles.
'texture' texture filename to use for effect.
'min_size' smallest particle size.
'max_size' largest particle size.
'radius' how far particles spread outward from center.
'gravity' gravity applied to particles once they spawn.
'glow' number between 1 and 15 for glowing particles.
'fall' when true particles fall, false has them rising, nil has them scatter.
Making Arrows Making Arrows
------------- -------------
@ -422,7 +455,9 @@ This function registers a arrow for mobs with the attack type shoot.
'on_step' is a custom function when arrow is active, nil for 'on_step' is a custom function when arrow is active, nil for
default. default.
'on_punch' is a custom function when arrow is punched, nil by default 'on_punch' is a custom function when arrow is punched, nil by default
'collisionbox' is hitbox table for arrow, {0,0,0,0,0,0} by default. 'collisionbox' is hitbox table for arrow, {-.1,-.1,-.1,.1,.1,.1} by default.
'lifetime' contains float value for how many seconds arrow exists in
world before being removed (default is 4.5 seconds).
Spawn Eggs Spawn Eggs

View File

@ -106,13 +106,17 @@ msgid "Mob Spawner"
msgstr "" msgstr ""
#: spawner.lua #: spawner.lua
msgid "Mob MinLight MaxLight Amount PlayerDist" msgid "(mob name) (min light) (max light) (amount) (player distance) (Y offset)"
msgstr "" msgstr ""
#: spawner.lua #: spawner.lua
msgid "Spawner Not Active (enter settings)" msgid "Spawner Not Active (enter settings)"
msgstr "" msgstr ""
#@ spawner.lua
msgid "Command:"
msgstr ""
#: spawner.lua #: spawner.lua
msgid "Spawner Active (@1)" msgid "Spawner Active (@1)"
msgstr "" msgstr ""

View File

@ -84,7 +84,7 @@ local function force_detach(player)
local entity = attached_to:get_luaentity() local entity = attached_to:get_luaentity()
if entity.driver if entity and entity.driver
and entity.driver == player then and entity.driver == player then
entity.driver = nil entity.driver = nil

View File

@ -24,7 +24,7 @@ Lucky Blocks: 9
Changelog: Changelog:
- 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 (default is 0 for unlimited), removed {immortal} from mob armor, fluid viscocity slows mobs
- 1.51 - Added some node checks for dangerous nodes, jumping and falling tweaks, spawn area check (thx for idea wuzzy), re-enabled mob suffocation, add 'mob_nospawn_range' setting - 1.51 - Added some node checks for dangerous nodes, jumping and falling tweaks, spawn area check (thx for idea wuzzy), re-enabled mob suffocation, add 'mob_nospawn_range' setting
- 1.50 - Added new line_of_sight function that uses raycasting if mt5.0 is found, (thanks Astrobe), dont spawn mobs if world anchor nearby (technic or simple_anchor mods), chinese local added - 1.50 - Added new line_of_sight function that uses raycasting if mt5.0 is found, (thanks Astrobe), dont spawn mobs if world anchor nearby (technic or simple_anchor mods), chinese local added
- 1.49- Added mobs:force_capture(self, player) function, api functions now use metatables thanks to bell07 - 1.49- Added mobs:force_capture(self, player) function, api functions now use metatables thanks to bell07

View File

@ -3,7 +3,7 @@ local S = mobs.intllib
-- mob spawner -- mob spawner
local spawner_default = "mobs_animal:pumba 10 15 0 0" local spawner_default = "mobs_animal:pumba 10 15 0 0 0"
minetest.register_node("mobs:spawner", { minetest.register_node("mobs:spawner", {
tiles = {"mob_spawner.png"}, tiles = {"mob_spawner.png"},
@ -17,10 +17,17 @@ minetest.register_node("mobs:spawner", {
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
-- setup formspec
local head = S("(mob name) (min light) (max light) (amount)"
.. " (player distance) (Y offset)")
-- text entry formspec -- text entry formspec
meta:set_string("formspec", meta:set_string("formspec",
"field[text;" .. S("Mob MinLight MaxLight Amount PlayerDist") "size[9,3.5]"
.. "label[0.15,0.5;" .. minetest.formspec_escape(head) .. "]"
.. "field[1,2.5;7.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)"))
meta:set_string("command", spawner_default) meta:set_string("command", spawner_default)
end, end,
@ -54,11 +61,11 @@ minetest.register_node("mobs:spawner", {
local pla = tonumber(comm[5]) -- player distance (0 to disable) local pla = tonumber(comm[5]) -- player distance (0 to disable)
local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob
if mob and mob ~= "" and mobs.spawning_mobs[mob] == true if mob and mob ~= "" and mobs.spawning_mobs[mob]
and num and num >= 0 and num <= 10 and num and num >= 0 and num <= 10
and mlig and mlig >= 0 and mlig <= 15 and mlig and mlig >= 0 and mlig <= 15
and xlig and xlig >= 0 and xlig <= 15 and xlig and xlig >= 0 and xlig <= 15
and pla and pla >=0 and pla <= 20 and pla and pla >= 0 and pla <= 20
and yof and yof > -10 and yof < 10 then and yof and yof > -10 and yof < 10 then
meta:set_string("command", fields.text) meta:set_string("command", fields.text)
@ -67,7 +74,7 @@ minetest.register_node("mobs:spawner", {
else else
minetest.chat_send_player(name, S("Mob Spawner settings failed!")) minetest.chat_send_player(name, S("Mob Spawner settings failed!"))
minetest.chat_send_player(name, minetest.chat_send_player(name,
S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] distance[1-20] y_offset[-10 to 10]”")) S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] player_distance[1-20] y_offset[-10 to 10]”"))
end end
end end
}) })