summaryrefslogtreecommitdiff
path: root/api.lua
diff options
context:
space:
mode:
Diffstat (limited to 'api.lua')
-rw-r--r--api.lua426
1 files changed, 191 insertions, 235 deletions
diff --git a/api.lua b/api.lua
index 71f47ba..ba44b82 100644
--- a/api.lua
+++ b/api.lua
@@ -1,9 +1,10 @@
--- Mobs Api (29th December 2016)
+-- Mobs Api (5th January 2017)
mobs = {}
mobs.mod = "redo"
+
-- Intllib
local S
if minetest.get_modpath("intllib") then
@@ -26,12 +27,14 @@ else
end
mobs.intllib = S
+
-- Invisibility mod check
mobs.invis = {}
if rawget(_G, "invisibility") then
mobs.invis = invisibility
end
+
-- Load settings
local damage_enabled = minetest.setting_getbool("enable_damage")
local peaceful_only = minetest.setting_getbool("only_peaceful_mobs")
@@ -75,24 +78,34 @@ local atan = function(x)
end
local atan2 = math.atan2
-do_attack = function(self, player)
- if self.state ~= "attack" then
+mob_sound = function(self, sound)
+
+ if sound then
+ minetest.sound_play(sound, {
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = self.sounds.distance
+ })
+ end
+end
- if random(0,100) < 90
- and self.sounds.war_cry then
- minetest.sound_play(self.sounds.war_cry, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
+do_attack = function(self, player)
+
+ if self.state == "attack" then
+ return
+ end
+
+ self.attack = player
+ self.state = "attack"
- self.state = "attack"
- self.attack = player
+ if random(0, 100) < 90 then
+ mob_sound(self, self.sounds.war_cry)
end
end
+
set_velocity = function(self, v)
local yaw = self.object:getyaw() + self.rotate or 0
@@ -104,6 +117,7 @@ set_velocity = function(self, v)
})
end
+
get_velocity = function(self)
local v = self.object:getvelocity()
@@ -111,113 +125,81 @@ get_velocity = function(self)
return (v.x * v.x + v.z * v.z) ^ 0.5
end
-set_animation = function(self, type)
- if not self.animation then
+set_anim = function(self, anim_start, anim_end, anim_speed, anim_name)
+
+ if not anim_start or not anim_end then
return
end
- 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
-
- if self.animation.stand_start
- and self.animation.stand_end then
-
- self.object:set_animation({
- x = self.animation.stand_start,
- y = self.animation.stand_end},
- (self.animation.speed_stand or self.animation.speed_normal), 0)
+ self.object:set_animation(
+ {x = anim_start, y = anim_end},
+ anim_speed or 15, 0)
- self.animation.current = "stand"
- end
-
- elseif type == "walk"
- and self.animation.current ~= "walk" then
-
- if self.animation.walk_start
- and self.animation.walk_end then
+ self.animation.current = anim_name
+end
- self.object:set_animation({
- x = self.animation.walk_start,
- y = self.animation.walk_end},
- (self.animation.speed_walk or self.animation.speed_normal), 0)
- self.animation.current = "walk"
- end
-
- elseif type == "run"
- and self.animation.current ~= "run" then
+set_animation = function(self, type)
- if self.animation.run_start
- and self.animation.run_end then
+ if not self.animation then
+ return
+ end
- 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.current = self.animation.current or ""
- self.animation.current = "run"
- end
+ if type == "stand" and self.animation.current ~= "stand" then
- elseif type == "punch"
- and self.animation.current ~= "punch" then
+ set_anim(self,
+ self.animation.stand_start,
+ self.animation.stand_end,
+ self.animation.speed_stand, "stand")
- if self.animation.punch_start
- and self.animation.punch_end then
+ elseif type == "walk" and self.animation.current ~= "walk" then
- self.object:set_animation({
- x = self.animation.punch_start,
- y = self.animation.punch_end},
- (self.animation.speed_punch or self.animation.speed_normal), 0)
+ set_anim(self,
+ self.animation.walk_start,
+ self.animation.walk_end,
+ self.animation.speed_walk, "walk")
- self.animation.current = "punch"
- end
- elseif type == "punch2"
- and self.animation.current ~= "punch2" then
+ elseif type == "run" and self.animation.current ~= "run" then
- if self.animation.punch2_start
- and self.animation.punch2_end then
+ set_anim(self,
+ self.animation.run_start,
+ self.animation.run_end,
+ self.animation.speed_run, "run")
- self.object:set_animation({
- x = self.animation.punch2_start,
- y = self.animation.punch2_end},
- (self.animation.speed_punch2 or self.animation.speed_normal), 0)
+ elseif type == "punch" and self.animation.current ~= "punch" then
- self.animation.current = "punch2"
- end
- elseif type == "shoot"
- and self.animation.current ~= "shoot" then
+ set_anim(self,
+ self.animation.punch_start,
+ self.animation.punch_end,
+ self.animation.speed_punch, "punch")
- if self.animation.shoot_start
- and self.animation.shoot_end then
+ elseif type == "punch2" and self.animation.current ~= "punch2" then
- self.object:set_animation({
- x = self.animation.shoot_start,
- y = self.animation.shoot_end},
- (self.animation.speed_shoot or self.animation.speed_normal), 0)
+ set_anim(self,
+ self.animation.punch2_start,
+ self.animation.punch2_end,
+ self.animation.speed_punch2, "punch2")
- self.animation.current = "shoot"
- end
- elseif type == "die"
- and self.animation.current ~= "die" then
+ elseif type == "shoot" and self.animation.current ~= "shoot" then
- if self.animation.die_start
- and self.animation.die_end then
+ set_anim(self,
+ self.animation.shoot_start,
+ self.animation.shoot_end,
+ self.animation.speed_shoot, "shoot")
- self.object:set_animation({
- x = self.animation.die_start,
- y = self.animation.die_end},
- (self.animation.speed_die or self.animation.speed_normal), 0)
+ elseif type == "die" and self.animation.current ~= "die" then
- self.animation.current = "die"
- end
+ set_anim(self,
+ self.animation.die_start,
+ self.animation.die_end,
+ self.animation.speed_die, "die")
end
end
+
-- check line of sight for walkers and swimmers alike
function line_of_sight_water(self, pos1, pos2, stepsize)
@@ -257,6 +239,7 @@ function line_of_sight_water(self, pos1, pos2, stepsize)
end
+
-- particle effects
function effect(pos, amount, texture, min_size, max_size, radius, gravity)
@@ -282,6 +265,7 @@ function effect(pos, amount, texture, min_size, max_size, radius, gravity)
})
end
+
-- update nametag colour
function update_tag(self)
@@ -307,6 +291,7 @@ function update_tag(self)
end
+
-- check if mob is dead or only hurt
function check_for_death(self)
@@ -320,14 +305,7 @@ function check_for_death(self)
-- still got some health? play hurt sound
if self.health > 0 then
- if self.sounds.damage then
-
- minetest.sound_play(self.sounds.damage, {
- object = self.object,
- gain = 1.0,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.damage)
-- make sure health isn't higher than max
if self.health > self.hp_max then
@@ -338,13 +316,15 @@ function check_for_death(self)
if not self.nametag2 then
self.nametag2 = self.nametag or ""
end
-if show_health then
- self.htimer = 2
- self.nametag = "health: " .. self.health .. " of " .. self.hp_max
+ if show_health then
+
+ self.htimer = 2
+ self.nametag = "health: " .. self.health .. " of " .. self.hp_max
+
+ update_tag(self)
+ end
- update_tag(self)
-end
return false
end
@@ -371,15 +351,7 @@ end
end
end
- -- play death sound
- if self.sounds.death then
-
- minetest.sound_play(self.sounds.death, {
- object = self.object,
- gain = 1.0,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.death)
-- execute custom death function
if self.on_die then
@@ -416,6 +388,7 @@ end
return true
end
+
-- check if within physical map limits (-30911 to 30927)
function within_limits(pos, radius)
@@ -431,6 +404,7 @@ function within_limits(pos, radius)
return false -- beyond limits
end
+
-- is mob facing a cliff
local function is_at_cliff(self)
@@ -455,6 +429,7 @@ local function is_at_cliff(self)
return false
end
+
-- get node but use fallback for nil or unknown
local function node_ok(pos, fallback)
@@ -473,6 +448,7 @@ local function node_ok(pos, fallback)
return minetest.registered_nodes[fallback]
end
+
-- environmental damage (water, lava, fire, light)
do_env_damage = function(self)
@@ -554,6 +530,7 @@ do_env_damage = function(self)
check_for_death(self)
end
+
-- jump if facing a solid node (not fences or gates)
do_jump = function(self)
@@ -605,17 +582,11 @@ do_jump = function(self)
self.object:setvelocity(v)
- if self.sounds.jump then
-
- minetest.sound_play(self.sounds.jump, {
- object = self.object,
- gain = 1.0,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.jump)
end
end
+
-- this is a faster way to calculate distance
local get_distance = function(a, b)
@@ -624,6 +595,7 @@ local get_distance = function(a, b)
return square(x * x + y * y + z * z)
end
+
-- blast damage to entities nearby (modified from TNT mod)
function entity_physics(pos, radius)
@@ -656,6 +628,7 @@ function entity_physics(pos, radius)
end
end
+
-- should mob follow what I'm holding ?
function follow_holding(self, clicker)
@@ -685,6 +658,7 @@ function follow_holding(self, clicker)
return false
end
+
-- find two animals of same type and breed if nearby and horny
local function breed(self)
@@ -819,6 +793,7 @@ local function breed(self)
end
end
+
-- find and replace what mob is looking for (grass, wheat etc.)
function replace(self, pos)
@@ -848,6 +823,7 @@ function replace(self, pos)
end
end
+
-- check if daytime and also if mob is docile during daylight hours
function day_docile(self)
@@ -863,6 +839,7 @@ function day_docile(self)
end
end
+
-- path finding and smart mob routine by rnd
function smart_mobs(self, s, p, dist, dtime)
@@ -992,26 +969,12 @@ function smart_mobs(self, s, p, dist, dtime)
self.path.stuck_timer = stuck_timeout - 2
-- frustration! cant find the damn path :(
- if self.sounds.random then
-
- minetest.sound_play(self.sounds.random, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
-
+ mob_sound(self, self.sounds.random)
else
-
-- yay i found path
- if self.sounds.attack then
+ mob_sound(self, self.sounds.attack)
- set_velocity(self, self.walk_velocity)
-
- minetest.sound_play(self.sounds.attack, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
+ set_velocity(self, self.walk_velocity)
-- follow path now that it has it
self.path.following = true
@@ -1019,6 +982,7 @@ function smart_mobs(self, s, p, dist, dtime)
end
end
+
-- specific attacks
local specific_attack = function(list, what)
@@ -1038,6 +1002,7 @@ local specific_attack = function(list, what)
return false
end
+
-- monster find someone to attack
local monster_attack = function(self)
@@ -1080,7 +1045,7 @@ local monster_attack = function(self)
-- find specific mob to attack, failing that attack player/npc/animal
if specific_attack(self.specific_attack, name)
and (type == "player" or type == "npc"
- or (type == "animal" and self.attack_animals == true)) then
+ or (type == "animal" and self.attack_animals == true)) then
s = self.object:getpos()
p = player:getpos()
@@ -1111,6 +1076,7 @@ local monster_attack = function(self)
end
end
+
-- npc, find closest monster to attack
local npc_attack = function(self)
@@ -1148,6 +1114,7 @@ local npc_attack = function(self)
end
end
+
-- follow player if owner or holding item, if fish outta water then flop
local follow_flop = function(self)
@@ -1267,6 +1234,7 @@ local follow_flop = function(self)
end
end
+
-- dogshoot attack switch and counter function
local dogswitch = function(self, dtime)
@@ -1292,6 +1260,7 @@ local dogswitch = function(self, dtime)
return self.dogshoot_switch
end
+
-- execute current state (stand, walk, run, attacks)
local do_states = function(self, dtime)
@@ -1552,14 +1521,7 @@ local do_states = function(self, dtime)
if minetest.find_node_near(pos, 1, {"group:water"})
or minetest.is_protected(pos, "") then
- if self.sounds.explode then
-
- minetest.sound_play(self.sounds.explode, {
- object = self.object,
- gain = 1.0,
- max_hear_distance = 16
- })
- end
+ mob_sound(self, self.sounds.explode)
self.object:remove()
@@ -1733,13 +1695,7 @@ local do_states = function(self, dtime)
if line_of_sight_water(self, p2, s2) == true then
-- play attack sound
- if self.sounds.attack then
-
- minetest.sound_play(self.sounds.attack, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.attack)
-- punch player (or what player is attached to)
local attached = self.attack:get_attach()
@@ -1791,13 +1747,7 @@ local do_states = function(self, dtime)
set_animation(self, "shoot")
-- play shoot attack sound
- if self.sounds.shoot_attack then
-
- minetest.sound_play(self.sounds.shoot_attack, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.shoot_attack)
local p = self.object:getpos()
@@ -1822,6 +1772,7 @@ local do_states = function(self, dtime)
end
end
+
-- falling and fall damage
local falling = function(self, pos)
@@ -1883,6 +1834,7 @@ local falling = function(self, pos)
end
end
+
local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
-- error checking when mod profiling is enabled
@@ -1957,81 +1909,80 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
hitter:set_wielded_item(weapon)
end
--- only play hit sound and show blood effects if damage is 1 or over
-if damage >= 1 then
+ -- only play hit sound and show blood effects if damage is 1 or over
+ if damage >= 1 then
- -- weapon sounds
- if weapon:get_definition().sounds ~= nil then
+ -- weapon sounds
+ if weapon:get_definition().sounds ~= nil then
- local s = random(0, #weapon:get_definition().sounds)
+ local s = random(0, #weapon:get_definition().sounds)
- minetest.sound_play(weapon:get_definition().sounds[s], {
- object = hitter,
- max_hear_distance = 8
- })
- else
- minetest.sound_play("default_punch", {
- object = hitter,
- max_hear_distance = 5
- })
- end
-
- -- blood_particles
- if self.blood_amount > 0
- and not disable_blood then
+ minetest.sound_play(weapon:get_definition().sounds[s], {
+ object = hitter,
+ max_hear_distance = 8
+ })
+ else
+ minetest.sound_play("default_punch", {
+ object = hitter,
+ max_hear_distance = 5
+ })
+ end
- local pos = self.object:getpos()
+ -- blood_particles
+ if self.blood_amount > 0
+ and not disable_blood then
- pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5
+ local pos = self.object:getpos()
- effect(pos, self.blood_amount, self.blood_texture)
- end
+ pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5
- -- do damage
- self.health = self.health - floor(damage)
+ effect(pos, self.blood_amount, self.blood_texture)
+ end
- -- exit here if dead
- if check_for_death(self) then
- return
- end
+ -- do damage
+ self.health = self.health - floor(damage)
- --[[ add healthy afterglow when hit (can cause hit lag with larger textures)
- core.after(0.1, function()
- self.object:settexturemod("^[colorize:#c9900070")
+ -- exit here if dead
+ if check_for_death(self) then
+ return
+ end
- core.after(0.3, function()
- self.object:settexturemod("")
- end)
- end) ]]
+ --[[ add healthy afterglow when hit (can cause hit lag with larger textures)
+ core.after(0.1, function()
+ self.object:settexturemod("^[colorize:#c9900070")
- -- knock back effect (only on full punch)
- if self.knock_back > 0
- and tflp > punch_interval then
+ core.after(0.3, function()
+ self.object:settexturemod("")
+ end)
+ end) ]]
- local v = self.object:getvelocity()
- local r = 1.4 - min(punch_interval, 1.4)
- local kb = r * 5
- local up = 2
+ -- knock back effect (only on full punch)
+ if self.knock_back > 0
+ and tflp > punch_interval then
- -- if already in air then dont go up anymore when hit
- if v.y > 0
- or self.fly then
- up = 0
- end
+ local v = self.object:getvelocity()
+ local r = 1.4 - min(punch_interval, 1.4)
+ local kb = r * 5
+ local up = 2
- -- direction error check
- dir = dir or {x = 0, y = 0, z = 0}
+ -- if already in air then dont go up anymore when hit
+ if v.y > 0
+ or self.fly then
+ up = 0
+ end
- self.object:setvelocity({
- x = dir.x * kb,
- y = up,
- z = dir.z * kb
- })
+ -- direction error check
+ dir = dir or {x = 0, y = 0, z = 0}
- self.pause_timer = r
- end
+ self.object:setvelocity({
+ x = dir.x * kb,
+ y = up,
+ z = dir.z * kb
+ })
-end -- END if damage
+ self.pause_timer = r
+ end
+ end -- END if damage
-- if skittish then run away
if self.runaway == true then
@@ -2087,6 +2038,7 @@ end -- END if damage
end
end
+
local mob_activate = function(self, staticdata, dtime_s, def)
-- remove monsters in peaceful mode, or when no data
@@ -2186,6 +2138,7 @@ local mob_activate = function(self, staticdata, dtime_s, def)
update_tag(self)
end
+
local mob_step = function(self, dtime)
local pos = self.object:getpos()
@@ -2270,13 +2223,8 @@ local mob_step = function(self, dtime)
replace(self, pos)
-- mob plays random sound at times
- if self.sounds.random
- and random(1, 100) == 1 then
-
- minetest.sound_play(self.sounds.random, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
+ if random(1, 100) == 1 then
+ mob_sound(self, self.sounds.random)
end
-- environmental damage timer (every 1 second)
@@ -2302,6 +2250,7 @@ local mob_step = function(self, dtime)
end
+
-- default function when mobs are blown up with TNT
local do_tnt = function(obj, damage)
@@ -2315,6 +2264,7 @@ local do_tnt = function(obj, damage)
return false, true, {}
end
+
mobs.spawning_mobs = {}
-- register mob function
@@ -2466,6 +2416,7 @@ minetest.register_entity(name, {
end -- END mobs:register_mob function
+
-- count how many mobs of one type are inside an area
local count_mobs = function(pos, type)
@@ -2488,6 +2439,7 @@ local count_mobs = function(pos, type)
return num
end
+
-- global functions
function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
@@ -2626,6 +2578,7 @@ 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)
@@ -2633,6 +2586,7 @@ function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_o
chance, active_object_count, -31000, max_height, day_toggle)
end
+
-- MarkBu's spawn function
function mobs:spawn(def)
@@ -2653,6 +2607,7 @@ function mobs:spawn(def)
chance, active_object_count, min_height, max_height, day_toggle, on_spawn)
end
+
-- set content id's
local c_air = minetest.get_content_id("air")
local c_ignore = minetest.get_content_id("ignore")
@@ -2746,6 +2701,7 @@ function mobs:explosion(pos, radius, fire, smoke, sound)
end
end
+
-- register arrow for shoot attack
function mobs:register_arrow(name, def)
@@ -2871,6 +2827,7 @@ function mobs:register_arrow(name, def)
})
end
+
-- Spawn Egg
function mobs:register_egg(mob, desc, background, addegg, no_creative)
@@ -2929,6 +2886,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
})
end
+
-- capture critter (thanks to blert2112 for idea)
function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, force_take, replacewith)
@@ -3006,6 +2964,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
end
end
+
-- protect tamed mob with rune iten
function mobs:protect(self, clicker)
@@ -3032,6 +2991,7 @@ function mobs:protect(self, clicker)
return false
end
+
local mob_obj = {}
local mob_sta = {}
@@ -3112,13 +3072,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
end
-- make sound when fed so many times
- if self.sounds.random then
-
- minetest.sound_play(self.sounds.random, {
- object = self.object,
- max_hear_distance = self.sounds.distance
- })
- end
+ mob_sound(self, self.sounds.random)
end
return true
@@ -3150,6 +3104,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
end
+
-- inspired by blockmen's nametag mod
minetest.register_on_player_receive_fields(function(player, formname, fields)
@@ -3185,6 +3140,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end)
+
-- compatibility function for old entities to new modpack entities
function mobs:alias_mob(old_name, new_name)