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

Compare commits

...

9 Commits

4 changed files with 161 additions and 87 deletions

191
api.lua
View File

@ -8,12 +8,12 @@ local use_cmi = minetest.global_exists("cmi")
mobs = { mobs = {
mod = "redo", mod = "redo",
version = "20210114", version = "20210407",
intllib = S, intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {} invis = minetest.global_exists("invisibility") and invisibility or {}
} }
-- localize math functions -- localize common functions
local pi = math.pi local pi = math.pi
local square = math.sqrt local square = math.sqrt
local sin = math.sin local sin = math.sin
@ -112,7 +112,8 @@ local mob_class = {
light_damage_min = 14, light_damage_min = 14,
light_damage_max = 15, light_damage_max = 15,
water_damage = 0, water_damage = 0,
lava_damage = 0, lava_damage = 4,
fire_damage = 4,
air_damage = 0, air_damage = 0,
suffocation = 2, suffocation = 2,
fall_damage = 1, fall_damage = 1,
@ -164,6 +165,7 @@ local mob_class = {
local mob_class_meta = {__index = mob_class} local mob_class_meta = {__index = mob_class}
-- play sound -- play sound
function mob_class:mob_sound(sound) function mob_class:mob_sound(sound)
@ -251,9 +253,17 @@ local check_for = function(look_for, look_inside)
for _, str in pairs(look_inside) do for _, str in pairs(look_inside) do
if str == look_for then if str == look_for then
return true return true
end end
if str:find("group:") then
local group = str:split(":")[2]
if minetest.get_item_group(look_for, group) ~= 0 then
return true
end
end
end end
end end
@ -539,12 +549,10 @@ local ray_line_of_sight = function(self, pos1, pos2)
return true return true
end end
-- detect if using minetest 5.0 by searching for permafrost node
local is_50 = minetest.registered_nodes["default:permafrost"]
function mob_class:line_of_sight(pos1, pos2, stepsize) function mob_class:line_of_sight(pos1, pos2, stepsize)
if is_50 then -- only use if minetest 5.0 is detected if minetest.raycast then -- only use if minetest 5.0 is detected
return ray_line_of_sight(self, pos1, pos2) return ray_line_of_sight(self, pos1, pos2)
end end
@ -976,7 +984,12 @@ local is_node_dangerous = function(self, nodename)
end end
if self.lava_damage > 0 if self.lava_damage > 0
and minetest.get_item_group(nodename, "igniter") ~= 0 then and minetest.get_item_group(nodename, "lava") ~= 0 then
return true
end
if self.fire_damage > 0
and minetest.get_item_group(nodename, "fire") ~= 0 then
return true return true
end end
@ -1062,9 +1075,8 @@ function mob_class:do_env_damage()
local nodef = minetest.registered_nodes[self.standing_in] local nodef = minetest.registered_nodes[self.standing_in]
-- water -- water
if self.water_damage and nodef.groups.water then if self.water_damage ~= 0
and nodef.groups.water then
if self.water_damage ~= 0 then
self.health = self.health - self.water_damage self.health = self.health - self.water_damage
@ -1074,12 +1086,10 @@ function mob_class:do_env_damage()
pos = pos, node = self.standing_in}) then pos = pos, node = self.standing_in}) then
return true return true
end end
end
-- ignition source (fire or lava) -- lava damage
elseif self.lava_damage and nodef.groups.igniter then elseif self.lava_damage ~= 0
and nodef.groups.lava then
if self.lava_damage ~= 0 then
self.health = self.health - self.lava_damage self.health = self.health - self.lava_damage
@ -1089,10 +1099,23 @@ function mob_class:do_env_damage()
node = self.standing_in, hot = true}) then node = self.standing_in, hot = true}) then
return true return true
end end
-- fire damage
elseif self.fire_damage ~= 0
and nodef.groups.fire then
self.health = self.health - self.fire_damage
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then
return true
end end
-- damage_per_second node check -- damage_per_second node check (not fire and lava)
elseif nodef.damage_per_second ~= 0 then elseif nodef.damage_per_second ~= 0
and nodef.groups.lava == 0 and nodef.groups.fire == 0 then
self.health = self.health - nodef.damage_per_second self.health = self.health - nodef.damage_per_second
@ -1306,10 +1329,19 @@ local entity_physics = function(pos, radius)
end end
-- can mob see player
local is_invisible = function(self, player_name)
if mobs.invis[player_name] and not self.ignore_invisibility then
return true
end
end
-- should mob follow what I'm holding ? -- should mob follow what I'm holding ?
function mob_class:follow_holding(clicker) function mob_class:follow_holding(clicker)
if mobs.invis[clicker:get_player_name()] then if is_invisible(self, clicker:get_player_name()) then
return false return false
end end
@ -1354,11 +1386,15 @@ function mob_class:breed()
self.on_grown(self) self.on_grown(self)
else else
-- jump when fully grown so as not to fall into ground -- jump when fully grown so as not to fall into ground
self.object:set_velocity({ -- self.object:set_velocity({
x = 0, -- x = 0,
y = self.jump_height, -- y = self.jump_height,
z = 0 -- z = 0
}) -- })
local pos = self.object:get_pos() ; if not pos then return end
local ent = self.object:get_luaentity()
pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4
self.object:set_pos(pos)
end end
end end
@ -1458,6 +1494,8 @@ function mob_class:breed()
effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5) effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5)
end end
pos.y = pos.y + 0.5 -- spawn child a little higher
local mob = minetest.add_entity(pos, self.name) local mob = minetest.add_entity(pos, self.name)
local ent2 = mob:get_luaentity() local ent2 = mob:get_luaentity()
local textures = self.base_texture local textures = self.base_texture
@ -1894,7 +1932,7 @@ function mob_class:general_attack()
if not damage_enabled if not damage_enabled
or self.attack_players == false or self.attack_players == false
or (self.owner and self.type ~= "monster") or (self.owner and self.type ~= "monster")
or mobs.invis[objs[n]:get_player_name()] or is_invisible(self, objs[n]:get_player_name())
or (self.specific_attack or (self.specific_attack
and not check_for("player", self.specific_attack)) then and not check_for("player", self.specific_attack)) then
objs[n] = nil objs[n] = nil
@ -1973,7 +2011,7 @@ function mob_class:do_runaway_from()
pname = objs[n]:get_player_name() pname = objs[n]:get_player_name()
if mobs.invis[pname] if is_invisible(self, pname)
or self.owner == pname then or self.owner == pname then
name = "" name = ""
@ -2038,7 +2076,7 @@ function mob_class:follow_flop()
for n = 1, #players do for n = 1, #players do
if get_distance(players[n]:get_pos(), s) < self.view_range if get_distance(players[n]:get_pos(), s) < self.view_range
and not mobs.invis[ players[n]:get_player_name() ] then and not is_invisible(self, players[n]:get_player_name()) then
self.following = players[n] self.following = players[n]
@ -2336,7 +2374,7 @@ function mob_class:do_states(dtime)
or not self.attack:get_pos() or not self.attack:get_pos()
or self.attack:get_hp() <= 0 or self.attack:get_hp() <= 0
or (self.attack:is_player() or (self.attack:is_player()
and mobs.invis[ self.attack:get_player_name() ]) then and is_invisible(self, self.attack:get_player_name())) then
--print(" ** stop attacking **", dist, self.view_range) --print(" ** stop attacking **", dist, self.view_range)
@ -2684,34 +2722,17 @@ function mob_class:falling(pos)
-- sanity check -- sanity check
if not v then return end if not v then return end
local fall_speed = -10 -- gravity local fall_speed = self.fall_speed
-- don't exceed mob fall speed
if v.y < self.fall_speed then
fall_speed = self.fall_speed
end
-- in water then use liquid viscosity for float/sink speed -- in water then use liquid viscosity for float/sink speed
if (self.standing_in if self.floats == 1 and self.standing_in
and minetest.registered_nodes[self.standing_in].groups.liquid) and minetest.registered_nodes[self.standing_in].groups.liquid then
or (self.standing_on
and minetest.registered_nodes[self.standing_in].groups.liquid) then
local visc = min( local visc = min(
minetest.registered_nodes[self.standing_in].liquid_viscosity, 7) minetest.registered_nodes[self.standing_in].liquid_viscosity, 7) + 1
if self.floats == 1 then self.object:set_velocity({x = v.x, y = 0.6, z = v.z})
fall_speed = -1.2 / visc
-- 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 else
-- fall damage onto solid ground -- fall damage onto solid ground
@ -2768,10 +2789,16 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
return true return true
end end
-- is mob protected? -- is mob protected
if self.protected and hitter:is_player() if self.protected then
and minetest.is_protected(self.object:get_pos(),
hitter:get_player_name()) then -- did player hit mob and if so is it in protected area
if hitter:is_player() then
local player_name = hitter:get_player_name()
if player_name ~= self.owner
and minetest.is_protected(self.object:get_pos(), player_name) then
minetest.chat_send_player(hitter:get_player_name(), minetest.chat_send_player(hitter:get_player_name(),
S("Mob has been protected!")) S("Mob has been protected!"))
@ -2779,6 +2806,22 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
return true return true
end end
-- if protection is on level 2 then dont let arrows harm mobs
elseif self.protected == 2 then
local ent = hitter and hitter:get_luaentity()
if ent and ent._is_arrow then
return true -- arrow entity
elseif not ent then
return true -- non entity
end
end
end
local weapon = hitter:get_wielded_item() local weapon = hitter:get_wielded_item()
local weapon_def = weapon:get_definition() or {} local weapon_def = weapon:get_definition() or {}
local punch_interval = 1.4 local punch_interval = 1.4
@ -2988,7 +3031,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
and self.child == false and self.child == false
and self.attack_players == true and self.attack_players == true
and hitter:get_player_name() ~= self.owner and hitter:get_player_name() ~= self.owner
and not mobs.invis[ name ] and not is_invisible(self, name)
and self.object ~= hitter then and self.object ~= hitter then
-- attack whoever punched mob -- attack whoever punched mob
@ -3145,8 +3188,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
def.textures = {def.textures} def.textures = {def.textures}
end end
self.base_texture = def.textures and self.base_texture = def.textures and def.textures[random(#def.textures)]
def.textures[random(#def.textures)]
self.base_mesh = def.mesh self.base_mesh = def.mesh
self.base_size = self.visual_size self.base_size = self.visual_size
self.base_colbox = self.collisionbox self.base_colbox = self.collisionbox
@ -3553,6 +3595,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,
fire_damage = def.fire_damage,
air_damage = def.air_damage, air_damage = def.air_damage,
suffocation = def.suffocation, suffocation = def.suffocation,
fall_damage = def.fall_damage, fall_damage = def.fall_damage,
@ -3611,6 +3654,7 @@ minetest.register_entity(name, setmetatable({
pushable = def.pushable, pushable = def.pushable,
stay_near = def.stay_near, stay_near = def.stay_near,
randomly_turn = def.randomly_turn ~= false, randomly_turn = def.randomly_turn ~= false,
ignore_invisibility = def.ignore_invisibility,
on_spawn = def.on_spawn, on_spawn = def.on_spawn,
@ -4455,8 +4499,9 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net,
return false return false
end end
-- cannot pick up if not owner -- cannot pick up if not owner (unless player has protection_bypass priv)
if self.owner ~= name and force_take == false then if not minetest.check_player_privs(name, "protection_bypass")
and self.owner ~= name and force_take == false then
minetest.chat_send_player(name, S("@1 is owner!", self.owner)) minetest.chat_send_player(name, S("@1 is owner!", self.owner))
@ -4557,19 +4602,21 @@ function mobs:protect(self, clicker)
local name = clicker:get_player_name() local name = clicker:get_player_name()
local tool = clicker:get_wielded_item() local tool = clicker:get_wielded_item()
local tool_name = tool:get_name()
if tool:get_name() ~= "mobs:protector" then if tool_name ~= "mobs:protector"
and tool_name ~= "mobs:protector2" then
return false return false
end end
if self.tamed == false then if not self.tamed then
minetest.chat_send_player(name, S("Not tamed!")) minetest.chat_send_player(name, S("Not tamed!"))
return true -- false return true
end end
if self.protected == true then if self.protected then
minetest.chat_send_player(name, S("Already protected!")) minetest.chat_send_player(name, S("Already protected!"))
return true -- false return true
end end
if not mobs.is_creative(clicker:get_player_name()) then if not mobs.is_creative(clicker:get_player_name()) then
@ -4577,9 +4624,15 @@ function mobs:protect(self, clicker)
clicker:set_wielded_item(tool) clicker:set_wielded_item(tool)
end end
-- set protection level
if tool_name == "mobs:protector" then
self.protected = true self.protected = true
else
self.protected = 2 ; self.fire_damage = 0
end
local pos = self.object:get_pos() local pos = self.object:get_pos()
pos.y = pos.y + self.collisionbox[2] + 0.5 pos.y = pos.y + self.collisionbox[2] + 0.5
effect(self.object:get_pos(), 25, "mobs_protect_particle.png", effect(self.object:get_pos(), 25, "mobs_protect_particle.png",
@ -4639,7 +4692,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
-- deduct 10% of the time to adulthood -- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + ( self.hornytimer = self.hornytimer + (
(CHILD_GROW_TIME - self.hornytimer) * 0.1) (CHILD_GROW_TIME - self.hornytimer) * 0.1)
print ("====", self.hornytimer) --print ("====", self.hornytimer)
return true return true
end end
@ -4677,12 +4730,12 @@ print ("====", self.hornytimer)
end end
local item = clicker:get_wielded_item() local item = clicker:get_wielded_item()
local name = clicker:get_player_name()
-- if mob has been tamed you can name it with a nametag -- if mob has been tamed you can name it with a nametag
if item:get_name() == "mobs:nametag" if item:get_name() == "mobs:nametag"
and clicker:get_player_name() == self.owner then and (name == self.owner
or minetest.check_player_privs(name, "protection_bypass")) then
local name = clicker:get_player_name()
-- store mob and nametag stack in external variables -- store mob and nametag stack in external variables
mob_obj[name] = self mob_obj[name] = self

View File

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

View File

@ -115,6 +115,22 @@ minetest.register_craft({
} }
}) })
-- level 2 protection rune
minetest.register_craftitem("mobs:protector2", {
description = S("Mob Protection Rune (Level 2)"),
inventory_image = "mobs_protector2.png",
groups = {flammable = 2}
})
minetest.register_craft({
output = "mobs:protector2",
recipe = {
{"mobs:protector", "default:mese_crystal", "mobs:protector"},
{"default:mese_crystal", "default:diamondblock", "default:mese_crystal"},
{"mobs:protector", "default:mese_crystal", "mobs:protector"}
}
})
-- saddle -- saddle
minetest.register_craftitem("mobs:saddle", { minetest.register_craftitem("mobs:saddle", {
description = S("Saddle"), description = S("Saddle"),

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B