1
0
mirror of https://codeberg.org/tenplus1/mobs_redo.git synced 2025-07-17 15:50:28 +02:00

Version MFF.

This commit is contained in:
sys4-fr
2018-09-08 01:45:44 +02:00
parent 4921956b60
commit 904780573c
269 changed files with 106655 additions and 260 deletions

389
api.lua Normal file → Executable file
View File

@ -1,6 +1,4 @@
-- Mobs Api (15th April 2016)
-- Mobs Api (4th March 2016)
mobs = {}
mobs.mod = "redo"
@ -79,8 +77,6 @@ set_animation = function(self, type)
self.animation.current = self.animation.current or ""
self.animation.speed_normal = self.animation.speed_normal or 15
if type == "stand"
and self.animation.current ~= "stand" then
@ -121,7 +117,7 @@ set_animation = function(self, type)
self.object:set_animation({
x = self.animation.run_start,
y = self.animation.run_end},
(self.animation.speed_run or self.animation.speed_normal), 0)
self.animation.speed_run, 0)
self.animation.current = "run"
end
@ -136,7 +132,7 @@ set_animation = function(self, type)
self.object:set_animation({
x = self.animation.punch_start,
y = self.animation.punch_end},
(self.animation.speed_punch or self.animation.speed_normal), 0)
self.animation.speed_normal, 0)
self.animation.current = "punch"
end
@ -172,19 +168,17 @@ function line_of_sight_water(self, pos1, pos2, stepsize)
end
-- particle effects
function effect(pos, amount, texture, max_size, radius)
radius = radius or 2
function effect(pos, amount, texture, max_size)
minetest.add_particlespawner({
amount = amount,
time = 0.25,
minpos = pos,
maxpos = pos,
minvel = {x = -radius, y = -radius, z = -radius},
maxvel = {x = radius, y = radius, z = radius},
minacc = {x = -radius, y = -radius, z = -radius},
maxacc = {x = radius, y = radius, z = radius},
minvel = {x = -0, y = -2, z = -0},
maxvel = {x = 2, y = 2, z = 2},
minacc = {x = -4, y = -4, z = -4},
maxacc = {x = 4, y = 4, z = 4},
minexptime = 0.1,
maxexptime = 1,
minsize = 0.5,
@ -221,15 +215,17 @@ end
-- check if mob is dead or only hurt
function check_for_death(self)
-- has health actually changed?
if self.health == self.old_health then
return
-- return if no change
local hp = self.object:get_hp()
if hp == self.health then
return false
end
self.old_health = self.health
-- still got some health? play hurt sound
if self.health > 0 then
if hp > 0 then
self.health = hp
if self.sounds.damage then
@ -240,11 +236,6 @@ function check_for_death(self)
})
end
-- make sure health isn't higher than max
if self.health > self.hp_max then
self.health = self.hp_max
end
update_tag(self)
return false
@ -375,7 +366,7 @@ do_env_damage = function(self)
and self.time_of_day < 0.8
and (minetest.get_node_light(pos) or 0) > 12 then
self.health = self.health - self.light_damage
self.object:set_hp(self.object:get_hp() - self.light_damage)
effect(pos, 5, "tnt_smoke.png")
end
@ -396,7 +387,7 @@ do_env_damage = function(self)
if self.water_damage ~= 0
and nodef.groups.water then
self.health = self.health - self.water_damage
self.object:set_hp(self.object:get_hp() - self.water_damage)
effect(pos, 5, "bubble.png")
end
@ -407,7 +398,7 @@ do_env_damage = function(self)
or self.standing_in == "fire:basic_flame"
or self.standing_in == "fire:permanent_flame") then
self.health = self.health - self.lava_damage
self.object:set_hp(self.object:get_hp() - self.lava_damage)
effect(pos, 5, "fire_basic_flame.png")
end
@ -456,9 +447,8 @@ do_jump = function(self)
--print ("in front:", nod.name, pos.y + 0.5)
if (minetest.registered_items[nod.name].walkable
if minetest.registered_items[nod.name].walkable
and not nod.name:find("fence")
and not nod.name:find("gate"))
or self.walk_chance == 0 then
local v = self.object:getvelocity()
@ -485,6 +475,26 @@ do_jump = function(self)
end
end
function calc_velocity(pos1, pos2, old_vel, power) --MFF we use this function
-- If the two positions are equal the vector will contain nan and crash the game
if (pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z) then
return {
x = 0,
y = 0,
z = 0
}
end
local vel = vector.direction(pos1, pos2)
vel = vector.normalize(vel)
vel = vector.multiply(vel, power)
local dist = vector.distance(pos1, pos2)
dist = math.max(dist, 1)
vel = vector.divide(vel, dist)
vel = vector.add(vel, old_vel)
return vel
end
-- this is a faster way to calculate distance
local get_distance = function(a, b)
@ -494,33 +504,27 @@ local get_distance = function(a, b)
end
-- blast damage to entities nearby (modified from TNT mod)
function entity_physics(pos, radius)
function entity_physics(pos, radius, self) --/MFF (Crabman|06/23/2015)add self to use punch function
radius = radius * 2
local objs = minetest.get_objects_inside_radius(pos, radius)
local obj_pos, dist
local obj_pos, obj_vel, dist
for _, obj in pairs(objs) do
obj_pos = obj:getpos()
dist = math.max(1, get_distance(pos, obj_pos))
local damage = math.floor((4 / dist) * radius)
local ent = obj:get_luaentity()
if obj:is_player() then
obj:set_hp(obj:get_hp() - damage)
else --if ent.health then
obj:punch(obj, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = damage},
}, nil)
end
--MFF DEBUT pumpkins
obj_vel = obj:getvelocity()
if obj_vel ~= nil then
if not (obj:get_entity_name() == "__builtin:item" and self.do_not_project_items) then
obj:setvelocity(calc_velocity(pos, obj_pos, obj_vel, radius * 10))
end
end --MFF FIN pumpkins
--dist = math.max(1, get_distance(pos, obj_pos))
--local damage = math.floor((4 / dist) * radius)
--obj:set_hp(obj:get_hp() - damage)
obj:punch(self.object, 1.0,{full_punch_interval=1.0, damage_groups = {fleshy=self.damage} })--/MFF (Crabman|06/23/2015) use punch
end
end
@ -882,13 +886,9 @@ function smart_mobs(self, s, p, dist, dtime)
end
end
mobs.spawning_mobs = {}
-- register mob function
function mobs:register_mob(name, def)
mobs.spawning_mobs[name] = true
minetest.register_entity(name, {
stepheight = def.stepheight or 0.6,
@ -938,7 +938,7 @@ minetest.register_entity(name, {
--fov = def.fov or 120,
passive = def.passive or false,
recovery_time = def.recovery_time or 0.5,
knock_back = def.knock_back or 3,
knock_back = def.knock_back or 1, --Modif MFF, default value is "or 3",
blood_amount = def.blood_amount or 5,
blood_texture = def.blood_texture or "mobs_blood.png",
shoot_offset = def.shoot_offset or 0,
@ -958,6 +958,7 @@ minetest.register_entity(name, {
health = 0,
reach = def.reach or 3,
htimer = 0,
do_not_project_items = def.do_not_project_items or false, --MFF pumpkins
child_texture = def.child_texture,
docile_by_day = def.docile_by_day or false,
time_of_day = 0.5,
@ -965,8 +966,6 @@ minetest.register_entity(name, {
runaway = def.runaway,
runaway_timer = 0,
pathfinding = def.pathfinding,
immune_to = def.immune_to or {},
explosion_radius = def.explosion_radius,
on_step = function(self, dtime)
@ -1048,8 +1047,7 @@ minetest.register_entity(name, {
if d > 5 then
--self.object:set_hp(self.object:get_hp() - math.floor(d - 5))
self.health = self.health - math.floor(d - 5)
self.object:set_hp(self.object:get_hp() - math.floor(d - 5))
effect(pos, 5, "tnt_smoke.png")
@ -1192,6 +1190,7 @@ minetest.register_entity(name, {
and self.state ~= "attack" then
local s = self.object:getpos()
local p, dist --MFF
local obj = nil
for _, oir in pairs(minetest.get_objects_inside_radius(s, self.view_range)) do
@ -1499,10 +1498,10 @@ minetest.register_entity(name, {
local dist = get_distance(p, s)
-- stop attacking if player or out of range
if dist > self.view_range
if (dist > self.view_range
or not self.attack
or not self.attack:getpos()
or self.attack:get_hp() <= 0 then
or self.attack:get_hp() <= 0) and not self.exploding then -- MFF
--print(" ** stop attacking **", dist, self.view_range)
self.state = "stand"
@ -1536,7 +1535,7 @@ minetest.register_entity(name, {
self.object:setyaw(yaw)
end
if dist > self.reach then
if dist > self.reach and not self.exploding then
if not self.v_start then
@ -1560,7 +1559,8 @@ minetest.register_entity(name, {
end
set_animation(self, "run")
else
else -- MFF(Mg|06/10/2016) #509
self.exploding = true --MFF
set_velocity(self, 0)
self.timer = self.timer + dtime
self.blinktimer = (self.blinktimer or 0) + dtime
@ -1581,10 +1581,9 @@ minetest.register_entity(name, {
if self.timer > 3 then
local pos = self.object:getpos()
local radius = self.explosion_radius or 1
-- hurt player/mobs caught in blast area
entity_physics(pos, radius)
entity_physics(pos, 3, self) --/MFF (Crabman|06/23/2015)add self to use punch function
-- dont damage anything if area protected or next to water
if minetest.find_node_near(pos, 1, {"group:water"})
@ -1608,7 +1607,7 @@ minetest.register_entity(name, {
pos.y = pos.y - 1
mobs:explosion(pos, radius, 0, 1, self.sounds.explode)
mobs:explosion(pos, 2, 0, 1, self.sounds.explode)
self.object:remove()
@ -1839,14 +1838,14 @@ minetest.register_entity(name, {
local obj = minetest.add_entity(p, self.arrow)
local ent = obj:get_luaentity()
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
local v = ent.velocity or 1 -- or set to default
local v = ent.velocity
ent.switch = 1
-- offset makes shoot aim accurate
vec.y = vec.y + self.shoot_offset
vec.x = vec.x * (v / amount)
vec.y = vec.y * (v / amount)
vec.z = vec.z * (v / amount)
vec.x = vec.x * v / amount
vec.y = vec.y * v / amount
vec.z = vec.z * v / amount
obj:setvelocity(vec)
end
@ -1861,45 +1860,17 @@ minetest.register_entity(name, {
dir = dir or {x = 0, y = 0, z = 0}
-- weapon wear
local attach = hitter:get_attach()
if attach and attach:get_luaentity() then
local luaentity = attach:get_luaentity()
if luaentity.driver then
luaentity.driver = nil
end
hitter:set_detach() --MFF (crabman|27/7/2015) anti usebug, immortal if attached
end
local weapon = hitter:get_wielded_item()
local punch_interval = 1.4
-- calculate mob damage
local damage = 0
local armor = self.object:get_armor_groups() or {}
local tmp
-- quick error check incase it ends up 0 (serialize.h check test)
if tflp == 0 then
tflp = 0.2
end
for group,_ in pairs(tool_capabilities.damage_groups) do
tmp = tflp / (tool_capabilities.full_punch_interval or 1.4)
if tmp < 0 then
tmp = 0.0
elseif tmp > 1 then
tmp = 1.0
end
damage = damage + (tool_capabilities.damage_groups[group] or 0)
* tmp * ((armor[group] or 0) / 100.0)
end
-- check for tool immunity or special damage
for _, no in pairs(self.immune_to) do
if no[1] == weapon:get_name() then
damage = no[2] or 0
break
end
end
-- print ("Mob Damage is", damage)
-- add weapon wear
if tool_capabilities then
punch_interval = tool_capabilities.full_punch_interval or 1.4
end
@ -1927,23 +1898,11 @@ minetest.register_entity(name, {
})
end
-- do damage
self.health = self.health - math.floor(damage)
-- exit here if dead
if check_for_death(self) then
return
end
-- add healthy afterglow when hit
core.after(0.1, function()
self.object:settexturemod("^[colorize:#c9900070")
core.after(0.3, function()
self.object:settexturemod("")
end)
end)
-- blood_particles
if self.blood_amount > 0
and not disable_blood then
@ -1955,9 +1914,8 @@ minetest.register_entity(name, {
effect(pos, self.blood_amount, self.blood_texture)
end
-- knock back effect (only on full punch)
if self.knock_back > 0
and tflp > punch_interval then
-- knock back effect
if self.knock_back > 0 then
local v = self.object:getvelocity()
local r = 1.4 - math.min(punch_interval, 1.4)
@ -2119,9 +2077,9 @@ minetest.register_entity(name, {
self.path.stuck_timer = 0 -- if stuck for too long search for path
-- end init
self.object:set_armor_groups({immortal = 1, fleshy = self.armor})
self.object:set_hp(self.health)
self.object:set_armor_groups({fleshy = self.armor})
self.old_y = self.object:getpos().y
self.old_health = self.health
self.object:setyaw((math.random(0, 360) - 180) / 180 * pi)
self.sounds.distance = self.sounds.distance or 10
self.textures = textures
@ -2183,8 +2141,68 @@ end -- END mobs:register_mob function
-- global functions
mobs.spawning_mobs = {}
function mobs:spawn_special(name, nodes, neighbors, interval, chance, active_object_count) -- MFF to special mobs
mobs.spawning_mobs[name] = true
-- chance override in minetest.conf for registered mob
local new_chance = tonumber(minetest.setting_get(name .. "_chance"))
if new_chance ~= nil then
if new_chance == 0 then
return
end
chance = new_chance
end
minetest.register_abm({
nodenames = nodes,
neighbors = neighbors,
interval = interval,
chance = chance,
action = function(pos, node, _, active_object_count_wider)
-- do not spawn if too many active entities in area
local count = 0
local objs = minetest.get_objects_inside_radius(pos, 60)
for k, obj in pairs(objs) do
if obj:get_luaentity() ~= nil and obj:get_luaentity().name == name then
count = count + 1
end
end
if count > active_object_count then
return
end
-- spawn above node
pos.y = pos.y + 1
-- only spawn away from player
local objs = minetest.get_objects_inside_radius(pos, 10)
for _,oir in pairs(objs) do
if oir:is_player() then
return
end
end
-- are we spawning inside solid nodes?
if minetest.registered_nodes[node_ok(pos).name].walkable == true then
return
end
pos.y = pos.y + 1
if minetest.registered_nodes[node_ok(pos).name].walkable == true then
return
end
-- spawn mob half block higher than ground
pos.y = pos.y - 0.5
minetest.add_entity(pos, name)
end
})
end
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
interval, chance, active_object_count, min_height, max_height, day_toggle)
interval, chance, active_object_count, min_height, max_height, spawn_in_area, day_toggle) --MFF crabman "spawn_in_area"
mobs.spawning_mobs[name] = true
-- chance override in minetest.conf for registered mob
local new_chance = tonumber(minetest.setting_get(name .. "_chance"))
@ -2192,7 +2210,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
if new_chance ~= nil then
if new_chance == 0 then
print("[Mobs Redo] " .. name .. " has spawning disabled")
--print("[Mobs Redo] " .. name .. " has spawning disabled")
return
end
@ -2209,11 +2227,12 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
interval = interval,
chance = chance,
action = function(pos, node, aoc, active_object_count_wider)
action = function(pos, node, _, active_object_count_wider)
-- do not spawn if too many active entities in area
if active_object_count_wider > active_object_count
or not mobs.spawning_mobs[name] then
or not mobs.spawning_mobs[name]
or not pos then --MFF fix crash
return
end
@ -2250,7 +2269,8 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
-- mobs cannot spawn in protected areas when enabled
if spawn_protected == 1
and minetest.is_protected(pos, "") then
and minetest.is_protected(pos, "")
and not spawn_in_area then --MFF crabman
return
end
@ -2294,10 +2314,10 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
end
-- compatibility with older mob registration
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle)
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, spawn_in_area, day_toggle)
mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30,
chance, active_object_count, -31000, max_height, day_toggle)
chance, active_object_count, -31000, max_height, spawn_in_area, day_toggle)
end
-- set content id's
@ -2349,7 +2369,8 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
p.y = pos.y + y
p.z = pos.z + z
if (x * x) + (y * y) + (z * z) <= (radius * radius) + pr:next(-radius, radius)
if p.y >= -19600 --MFF
and(x * x) + (y * y) + (z * z) <= (radius * radius) + pr:next(-radius, radius)
and data[vi] ~= c_air
and data[vi] ~= c_ignore
and data[vi] ~= c_obsidian
@ -2360,8 +2381,48 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
local on_blast = minetest.registered_nodes[n].on_blast
if on_blast then
return on_blast(p)
else
local drops = on_blast(p) or {} -- MFF(Lymkwi) : Chests and bones return their drops now
for _, name in ipairs(drops) do
local obj = minetest.add_item(p, ItemStack(name))
if obj then
obj:setvelocity({
x = math.random(-2, 2),
y = 7,
z = math.random(-2, 2)
})
end
end
return
end
if not minetest.is_protected(p, "") --/MFF (Crabman|06/23/2015) re-added node protected in areas
and minetest.get_item_group(n, "unbreakable") ~= 1
and minetest.get_item_group(n, "nether") == 0 then
-- if chest then drop items inside
if n == "default:chest"
or n == "3dchest:chest"
or n == "bones:bones" then
local meta = minetest.get_meta(p)
local inv = meta:get_inventory()
for i = 1, inv:get_size("main") do
local m_stack = inv:get_stack("main", i)
local obj = minetest.add_item(p, m_stack)
if obj then
obj:setvelocity({
x = math.random(-2, 2),
y = 7,
z = math.random(-2, 2)
})
end
end
end
-- after effects
if fire > 0
and (minetest.registered_nodes[n].groups.flammable
@ -2420,13 +2481,6 @@ function mobs:register_arrow(name, def)
return
end
-- does arrow have a tail (fireball)
if def.tail
and def.tail == 1
and def.tail_texture then
effect(pos, 1, def.tail_texture, 10, 0)
end
if self.hit_node then
local node = node_ok(pos).name
@ -2488,30 +2542,20 @@ function mobs:register_arrow(name, def)
end
-- Spawn Egg
function mobs:register_egg(mob, desc, background, addegg, no_creative)
local grp = {}
-- do NOT add this egg to creative inventory (e.g. dungeon master)
if creative and no_creative == true then
grp = {not_in_creative_inventory = 1}
end
function mobs:register_egg(mob, desc, background, addegg)
local invimg = background
if addegg == 1 then
invimg = "mobs_chicken_egg.png^(" .. invimg ..
"^[mask:mobs_chicken_egg_overlay.png)"
invimg = invimg .. "^mobs_egg_inv.png" -- MFF
end
minetest.register_craftitem(mob, {
description = desc,
inventory_image = invimg,
groups = grp,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if pos
@ -2523,11 +2567,6 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
local mob = minetest.add_entity(pos, mob)
local ent = mob:get_luaentity()
if not ent then
mob:remove()
return
end
if ent.type ~= "monster" then
-- set owner and tame if not monster
ent.owner = placer:get_player_name()
@ -2774,41 +2813,3 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end)
-- used to drop items inside a chest or container
local drop_items = function(pos, invstring)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
for i = 1, inv:get_size(invstring) do
local m_stack = inv:get_stack(invstring, i)
local obj = minetest.add_item(pos, m_stack)
if obj then
obj:setvelocity({
x = math.random(-10, 10) / 9,
y = 3,
z = math.random(-10, 10) / 9
})
end
end
end
-- override chest node so it drops items on explode
minetest.override_item("default:chest", {
on_blast = function(p)
minetest.after(0, function()
drop_items(p, "main")
minetest.remove_node(p)
end)
end,
})