1
0
mirror of https://codeberg.org/tenplus1/mobs_redo.git synced 2025-07-27 04:24:35 +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 = {
mod = "redo",
version = "20200619",
version = "20200701",
intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {}
}
@ -206,7 +206,6 @@ end
function mob_class:collision()
local pos = self.object:get_pos()
local vel = self.object:get_velocity()
local x, z = 0, 0
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
@ -229,12 +228,36 @@ function mob_class:collision()
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
function mob_class:set_velocity(v)
-- halt mob if it has been ordered to stay
if self.order == "stand" then
self.object:set_velocity({x = 0, y = 0, z = 0})
return
end
@ -250,14 +273,26 @@ function mob_class:set_velocity(v)
-- nil check for velocity
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
local vel = self.object:get_velocity()
self.object:set_velocity({
x = max(-10, min((sin(yaw) * -v) + c_x, 10)),
y = max(-10, min((vel and vel.y or 0), 10)),
z = max(-10, min((cos(yaw) * v) + c_y, 10))
})
local new_vel = {
x = (sin(yaw) * -v) + c_x,
y = vel.y,
z = (cos(yaw) * v) + c_y
}
self.object:set_velocity(new_vel)
end
-- global version of above function
@ -550,20 +585,9 @@ function mob_class:flight_check()
if not def then return false end
if type(self.fly_in) == "string"
and self.standing_in == self.fly_in then
-- are we standing inside what we should be to fly/swim ?
if check_for(self.standing_in, self.fly_in) then
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
-- 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
gravity = gravity or -10
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({
amount = amount,
@ -665,6 +696,12 @@ local effect = function(pos, amount, texture, min_size, max_size,
})
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
function mob_class:update_tag()
@ -1107,14 +1144,8 @@ function mob_class:do_jump()
-- sanity check
if not yaw then return false end
-- what is mob standing on?
pos.y = pos.y + self.collisionbox[2] - 0.2
local nod = node_ok(pos)
--print("standing on:", nod.name, pos.y)
if minetest.registered_nodes[nod.name].walkable == false then
-- we can only jump if standing on solid node
if minetest.registered_nodes[self.standing_on].walkable == false then
return false
end
@ -1122,22 +1153,22 @@ function mob_class:do_jump()
local dir_x = -sin(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?
local nod = node_ok({
x = pos.x + dir_x,
y = pos.y + 0.5,
z = pos.z + dir_z
x = pos.x + dir_x, y = pos.y + 0.5, z = pos.z + dir_z
})
-- what is above and in front?
local nodt = node_ok({
x = pos.x + dir_x,
y = pos.y + 1.5,
z = pos.z + dir_z
x = pos.x + dir_x, y = pos.y + 1.5, z = pos.z + dir_z
})
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 above:", nodt.name, pos.y + 1.5)
@ -1239,22 +1270,10 @@ function mob_class:follow_holding(clicker)
end
local item = clicker:get_wielded_item()
local t = type(self.follow)
-- single item
if t == "string"
and item:get_name() == self.follow then
-- are we holding an item mob can follow ?
if check_for(item:get_name(), self.follow) then
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
return false
@ -1944,8 +1963,8 @@ function mob_class:do_runaway_from()
if name ~= "" and name ~= self.name
and specific_runaway(self.runaway_from, name) then
p = player:get_pos()
sp = s
p = player and player:get_pos() or s
-- aim higher to make looking up hills more realistic
p.y = p.y + 1
@ -2352,10 +2371,10 @@ function mob_class:do_states(dtime)
self.blinktimer = 0
if self.blinkstatus then
-- self.object:set_texture_mod("")
self.object:set_texture_mod(self.texture_mods)
else
-- self.object:set_texture_mod("^[brighten")
self.object:set_texture_mod(self.texture_mods
.. "^[brighten")
end
@ -2567,11 +2586,7 @@ function mob_class:do_states(dtime)
p.y = p.y - .5
s.y = s.y + .5
local vec = {
x = p.x - s.x,
y = p.y - s.y,
z = p.z - s.z
}
local vec = {x = p.x - s.x, y = p.y - s.y, z = p.z - s.z}
yaw = yaw_to_pos(self, p)
@ -2628,39 +2643,33 @@ function mob_class:falling(pos)
-- sanity check
if not v then return end
if v.y > 0 then
local fall_speed = -10 -- gravity
-- apply gravity when moving up
self.object:set_acceleration({
x = 0,
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})
-- don't exceed mob fall speed
if v.y < self.fall_speed then
fall_speed = self.fall_speed
end
-- in water then float up
if self.standing_in
and minetest.registered_nodes[self.standing_in].groups.water then
-- in water then use liquid viscosity for float/sink speed
if (self.standing_in
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
self.object:set_acceleration({
x = 0,
y = -self.fall_speed / (max(1, v.y) ^ 8), -- 8 was 2
z = 0
})
-- 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
else
@ -2684,6 +2693,13 @@ function mob_class:falling(pos)
self.old_y = self.object:get_pos().y
end
end
-- fall at set speed
self.object:set_acceleration({
x = 0,
y = fall_speed,
z = 0
})
end
@ -3170,6 +3186,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
self.selectionbox = selbox
self.visual_size = vis_size
self.standing_in = "air"
self.standing_on = "air"
-- check existing nametag
if not self.nametag then
@ -3296,6 +3313,9 @@ function mob_class:on_step(dtime, moveresult)
self.standing_in = node_ok({
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)
-- if standing inside solid block then jump to escape
@ -3451,7 +3471,7 @@ mobs.spawning_mobs = {}
-- register mob entity
function mobs:register_mob(name, def)
mobs.spawning_mobs[name] = true
mobs.spawning_mobs[name] = {}
minetest.register_entity(name, setmetatable({
@ -3598,6 +3618,106 @@ end
-- 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)
-- global function to add additional spawn checks
-- 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)
-- Do mobs spawn at all?
if not mobs_spawn then
if not mobs_spawn or not mobs.spawning_mobs[name] then
return
end
@ -3632,6 +3752,8 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
end
mobs.spawning_mobs[name].aoc = aoc
minetest.register_abm({
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
collisionbox = def.collisionbox or {-.1, -.1, -.1, .1, .1, .1},
timer = 0,
lifetime = def.lifetime or 4.5,
switch = 0,
owner_id = def.owner_id,
rotate = def.rotate,
@ -3876,11 +3999,11 @@ function mobs:register_arrow(name, def)
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()
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")

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
melee attack, parameters are (self, to_attack) and if true
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
active and which has access to all of the self.* variables
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
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
----------------------
@ -387,6 +402,24 @@ true the mob will not spawn.
'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
-------------
@ -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
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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ Lucky Blocks: 9
Changelog:
- 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.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

View File

@ -3,7 +3,7 @@ local S = mobs.intllib
-- 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", {
tiles = {"mob_spawner.png"},
@ -17,10 +17,17 @@ minetest.register_node("mobs:spawner", {
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
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}]")
meta:set_string("infotext", S("Spawner Not Active (enter settings)"))
meta:set_string("command", spawner_default)
end,
@ -54,11 +61,11 @@ minetest.register_node("mobs:spawner", {
local pla = tonumber(comm[5]) -- player distance (0 to disable)
local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob
if mob and mob ~= "" and mobs.spawning_mobs[mob] == true
if mob and mob ~= "" and mobs.spawning_mobs[mob]
and num and num >= 0 and num <= 10
and mlig and mlig >= 0 and mlig <= 15
and xlig and xlig >= 0 and xlig <= 15
and pla and pla >=0 and pla <= 20
and pla and pla >= 0 and pla <= 20
and yof and yof > -10 and yof < 10 then
meta:set_string("command", fields.text)
@ -67,7 +74,7 @@ minetest.register_node("mobs:spawner", {
else
minetest.chat_send_player(name, S("Mob Spawner settings failed!"))
minetest.chat_send_player(name,
S("Syntax: “name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] 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
})