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

Compare commits

...

24 Commits

Author SHA1 Message Date
ca34cc2274 fix api typo (thanks bastrabun :) 2022-05-21 08:04:38 +01:00
168014b86f tidy api 2022-05-14 11:21:36 +01:00
6f8b6fe3f5 select proper animation for flying mobs 2022-05-01 08:15:25 +01:00
dd16d63e8e revert hover 2022-04-30 14:35:59 +01:00
7bb5e2b382 add "hover" animation 2022-04-30 12:26:36 +01:00
7b429df9e9 tweak riding functions 2022-04-21 08:28:35 +01:00
0e72f0ca81 tweak mobs.drive() speed (thanks auouymous) 2022-04-18 08:31:25 +01:00
fb42be6b28 nil checks 2022-03-14 08:29:25 +00:00
f54c3da9d7 add nil check 2022-03-13 16:30:20 +00:00
65e369e5fc add 0.4.x compatibility when riding mod 2022-03-01 09:04:38 +00:00
9f74408792 remove owner infotext if no owner present 2022-02-05 12:25:01 +00:00
18c7f0a422 update translation checks (thanks mckaygerhard) 2022-01-20 08:54:08 +00:00
2fb7bf2c66 update api.txt for mob_object change 2022-01-18 06:41:29 +00:00
f01e8a61d0 rename var 2022-01-16 07:44:53 +00:00
b756aa50f5 fix crash (thanks SwissalpS) 2022-01-16 07:05:49 +00:00
e83620553d add mobs:is_node_dangerous(self, nodename) global function 2022-01-15 09:41:21 +00:00
e5d1958e16 add nil checks for riding mobs 2022-01-03 17:35:51 +00:00
6a4a02f3fb fix translations (thanks nixnoxus) 2021-12-12 08:13:54 +00:00
5d88766b74 add pointed_thing to on_rightclick vars 2021-11-16 20:22:15 +00:00
d31da2d069 mod loaded msg 2021-11-14 14:21:32 +00:00
00db86c924 fix intllib return 2021-11-14 14:18:28 +00:00
26ec61ee29 lasso can pick up animal babies 2021-09-20 10:49:19 +01:00
a8ca00dc56 fix self.follow list 2021-09-05 08:16:40 +01:00
4c80a55c04 add breeding info on hover and items followed on shift+rightclick mob (thanks nixnoxus) 2021-08-16 10:48:16 +01:00
9 changed files with 171 additions and 97 deletions

168
api.lua
View File

@ -1,14 +1,34 @@
-- Load support for intllib.
local MP = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator and minetest.get_translator("mobs_redo") or
dofile(MP .. "/intllib.lua")
-- Check for translation method
local S
if minetest.get_translator ~= nil then
S = minetest.get_translator("mobs") -- 5.x translation function
else
if minetest.get_modpath("intllib") then
dofile(minetest.get_modpath("intllib") .. "/init.lua")
if intllib.make_gettext_pair then
gettext, ngettext = intllib.make_gettext_pair() -- new gettext method
else
gettext = intllib.Getter() -- old text file method
end
S = gettext
else -- boilerplate function
S = function(str, ...)
local args = {...}
return str:gsub("@%d+", function(match)
return args[tonumber(match:sub(2))]
end)
end
end
end
-- CMI support check
local use_cmi = minetest.global_exists("cmi")
mobs = {
mod = "redo",
version = "20210801",
version = "20220514",
intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {}
}
@ -160,6 +180,7 @@ local mob_class = {
attack_players = true,
attack_npcs = true,
facing_fence = false,
_breed_countdown = nil,
_cmi_is_mob = true
}
@ -253,9 +274,9 @@ local check_for = function(look_for, look_inside)
return true
end
if str:find("group:") then
if str and str:find("group:") then
local group = str:split(":")[2]
local group = str:split(":")[2] or ""
if minetest.get_item_group(look_for, group) ~= 0 then
return true
@ -525,6 +546,7 @@ local new_line_of_sight = function(self, pos1, pos2, stepsize)
return false
end
-- check line of sight using raycasting (thanks Astrobe)
local ray_line_of_sight = function(self, pos1, pos2)
@ -722,6 +744,13 @@ function mobs:effect(pos, amount, texture, min_size, max_size,
end
-- Thanks Wuzzy for the following editable settings
local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 60 * 5 -- 5 minutes
local CHILD_GROW_TIME = 60 * 20 -- 20 minutes
-- update nametag colour
function mob_class:update_tag()
@ -740,9 +769,25 @@ function mob_class:update_tag()
col = "#FF0000"
end
-- build infotext
local text = ""
if self.horny == true then
text = "\nLoving: " .. (self.hornytimer - (HORNY_TIME + HORNY_AGAIN_TIME))
elseif self.child == true then
text = "\nGrowing: " .. (self.hornytimer - CHILD_GROW_TIME)
elseif self._breed_countdown then
text = "\nBreeding: " .. self._breed_countdown
end
self.infotext = "Health: " .. self.health .. " / " .. self.hp_max
.. "\n" .. "Owner: " .. self.owner
.. (self.owner == "" and "" or "\n" .. "Owner: " .. self.owner)
.. text
-- set changes
self.object:set_properties({
@ -870,18 +915,7 @@ function mob_class:check_for_death(cmi_cause)
self.health = self.hp_max
end
-- backup nametag so we can show health stats
-- if not self.nametag2 then
-- self.nametag2 = self.nametag or ""
-- end
-- if show_health
-- and (cmi_cause and cmi_cause.type == "punch") then
-- self.htimer = 2
-- self.nametag = "♥ " .. self.health .. " / " .. self.hp_max
self:update_tag()
-- end
return false
end
@ -978,19 +1012,19 @@ end
-- Returns true is node can deal damage to self
local is_node_dangerous = function(self, nodename)
function mobs:is_node_dangerous(mob_object, nodename)
if self.water_damage > 0
if mob_object.water_damage > 0
and minetest.get_item_group(nodename, "water") ~= 0 then
return true
end
if self.lava_damage > 0
if mob_object.lava_damage > 0
and minetest.get_item_group(nodename, "lava") ~= 0 then
return true
end
if self.fire_damage > 0
if mob_object.fire_damage > 0
and minetest.get_item_group(nodename, "fire") ~= 0 then
return true
end
@ -1002,11 +1036,15 @@ local is_node_dangerous = function(self, nodename)
return false
end
local function is_node_dangerous(mob_object, nodename)
return mobs:is_node_dangerous(mob_object, nodename)
end
-- is mob facing a cliff
function mob_class:is_at_cliff()
if self.fear_height == 0 then -- 0 for no falling protection!
if self.driver or self.fear_height == 0 then -- 0 for no falling protection!
return false
end
@ -1050,14 +1088,7 @@ function mob_class:do_env_damage()
self.htimer = self.htimer - 1
end
-- reset nametag after showing health stats
-- if self.htimer < 1 and self.nametag2 then
-- self.nametag = self.nametag2
-- self.nametag2 = nil
self:update_tag()
-- end
local pos = self.object:get_pos() ; if not pos then return end
@ -1358,10 +1389,6 @@ function mob_class:follow_holding(clicker)
return false
end
-- Thanks Wuzzy for the following editable settings
local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 60 * 5 -- 5 minutes
local CHILD_GROW_TIME = 60 * 20 -- 20 minutes
-- find two animals of same type and breed if nearby and horny
function mob_class:breed()
@ -1414,6 +1441,8 @@ function mob_class:breed()
self.hornytimer = 0
self.horny = false
end
self:update_tag()
end
-- find another same animal who is also horny and mate if nearby
@ -1469,6 +1498,8 @@ function mob_class:breed()
self.hornytimer = HORNY_TIME + 1
ent.hornytimer = HORNY_TIME + 1
self:update_tag()
-- have we reached active mob limit
if active_limit > 0 and active_mobs >= active_limit then
minetest.chat_send_player(self.owner,
@ -1656,6 +1687,7 @@ end
local pathfinder_mod = minetest.get_modpath("pathfinder")
-- path finding and smart mob routine by rnd,
-- line_of_sight and other edits by Elkien3
function mob_class:smart_mobs(s, p, dist, dtime)
@ -2084,7 +2116,7 @@ function mob_class:follow_flop()
for n = 1, #players do
if get_distance(players[n]:get_pos(), s) < self.view_range
if players[n] and get_distance(players[n]:get_pos(), s) < self.view_range
and not is_invisible(self, players[n]:get_player_name()) then
self.following = players[n]
@ -2341,11 +2373,22 @@ function mob_class:do_states(dtime)
else
self:set_velocity(self.walk_velocity)
-- figure out which animation to use while in motion
if self:flight_check()
and self.animation
and self.animation.fly_start
and self.animation.fly_end then
local on_ground = minetest.registered_nodes[self.standing_on].walkable
local in_water = minetest.registered_nodes[self.standing_in].groups.water
if on_ground and in_water then
self:set_animation("fly")
elseif on_ground then
self:set_animation("walk")
else
self:set_animation("fly")
end
else
self:set_animation("walk")
end
@ -2965,7 +3008,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
if self:check_for_death({type = "punch", puncher = hitter, hot = hot}) then
return true
end
end -- END if damage
end
-- knock back effect (only on full punch)
if self.knock_back and tflp >= punch_interval then
@ -3108,8 +3151,6 @@ function mob_class:mob_staticdata()
end
end
--print('===== '..self.name..'\n'.. dump(tmp)..'\n=====\n')
return minetest.serialize(tmp)
end
@ -3320,8 +3361,7 @@ function mob_class:mob_expire(pos, dtime)
end
end
-- minetest.log("action",
-- S("lifetimer expired, removed @1", self.name))
-- minetest.log("action", S("lifetimer expired, removed @1", self.name))
effect(pos, 15, "tnt_smoke.png", 2, 4, 2, 0)
@ -3348,9 +3388,9 @@ function mob_class:on_step(dtime, moveresult)
-- early warning check, if no yaw then no entity, skip rest of function
if not yaw then return end
-- get node at foot level every quarter second
self.node_timer = (self.node_timer or 0) + dtime
-- get nodes above and below foot level every 1/4 second
if self.node_timer > 0.25 then
self.node_timer = 0
@ -3648,7 +3688,7 @@ minetest.register_entity(name, setmetatable({
get_staticdata = function(self)
return self:mob_staticdata(self)
end,
end
}, mob_class_meta))
@ -4313,7 +4353,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
if def and def.on_rightclick then
return def.on_rightclick(
pointed_thing.under, under, placer, itemstack)
pointed_thing.under, under, placer, itemstack, pointed_thing)
end
if pos
@ -4364,7 +4404,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
if def and def.on_rightclick then
return def.on_rightclick(
pointed_thing.under, under, placer, itemstack)
pointed_thing.under, under, placer, itemstack, pointed_thing)
end
if pos
@ -4450,7 +4490,7 @@ end
function mobs:capture_mob(self, clicker, chance_hand, chance_net,
chance_lasso, force_take, replacewith)
if self.child
if not self
or not clicker:is_player()
or not clicker:get_inventory() then
return false
@ -4654,38 +4694,28 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
if self.health >= self.hp_max then
self.health = self.hp_max
-- if self.htimer < 1 then
-- minetest.chat_send_player(clicker:get_player_name(),
-- S("@1 at full health (@2)",
-- self.name:split(":")[2], tostring(self.health)))
-- self.htimer = 5
-- end
end
self.object:set_hp(self.health)
self:update_tag()
-- make children grow quicker
if self.child == true then
-- self.hornytimer = self.hornytimer + 20
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + (
(CHILD_GROW_TIME - self.hornytimer) * 0.1)
self.hornytimer = math.floor(self.hornytimer + (
(CHILD_GROW_TIME - self.hornytimer) * 0.1))
--print ("====", self.hornytimer)
return true
end
-- feed and tame
self.food = (self.food or 0) + 1
self._breed_countdown = feed_count - self.food
if self.food >= feed_count then
self.food = 0
self._breed_countdown = nil
if breed and self.hornytimer == 0 then
self.horny = true
@ -4711,6 +4741,8 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
self:mob_sound(self.sounds.random)
end
self:update_tag()
return true
end
@ -4740,6 +4772,22 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
return true
end
-- if mob follows items and user right clicks while holding sneak it shows info
if self.follow then
if clicker:get_player_control().sneak then
if type(self.follow) == "string" then
self.follow = {self.follow}
end
minetest.chat_send_player(clicker:get_player_name(),
S("@1 follows:\n- @2",
self.name:split(":")[2],
table.concat(self.follow, "\n- ")))
end
end
return false
end

View File

@ -415,7 +415,7 @@ the mobs:spawn, so it is recommended to use the above instead.
mobs:register_spawn(name, nodes, max_light, min_light, chance,
active_object_count, max_height, day_toggle)
mobs:spawn_specfic(name, nodes, neighbors, min_light, max_light, interval,
mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval,
chance, active_object_count, min_height, max_height, day_toggle, on_spawn)
A simpler way to handle mob spawns has been added with the mobs:spawn(def)
@ -691,6 +691,12 @@ space to spawn mob [name], if so then a new position is returned for use,
otherwise nil is returned.
mobs:is_node_dangerous(mob_object, nodename)
This function returns true if the node name given is harmful to the mob (mob_object),
it is mainly used when a mob is near a node it has to avoid.
External Settings for "minetest.conf"
------------------------------------

View File

@ -8,3 +8,4 @@ lucky_block?
cmi?
toolranks?
pathfinder?
player_api?

View File

@ -22,4 +22,4 @@ dofile(path .. "/spawner.lua")
-- Lucky Blocks
dofile(path .. "/lucky_block.lua")
minetest.log("action", "[MOD] Mobs Redo loaded")
print("[MOD] Mobs Redo loaded")

View File

@ -1,3 +0,0 @@
-- Support for the old multi-load method
dofile(minetest.get_modpath("intllib").."/init.lua")

View File

@ -11,7 +11,7 @@ msgstr ""
"PO-Revision-Date: 2017-07-02 14:27+0200\n"
"Last-Translator: Wuzzy <almikes@aol.com>\n"
"Language-Team: \n"
"Language: de_DE\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@ -1,4 +1,4 @@
name = mobs
depends =
optional_depends = default, tnt, dye, farming, invisibility, intllib, lucky_block, cmi, toolranks, pathfinder
optional_depends = default, tnt, dye, farming, invisibility, intllib, lucky_block, cmi, toolranks, pathfinder, player_api
description = Adds a mob api for mods to add animals or monsters etc.

View File

@ -1,14 +1,16 @@
-- lib_mount by Blert2112 (edited by TenPlus1)
local is_50 = minetest.get_modpath("player_api") -- 5.x compatibility
local abs, cos, floor, sin, sqrt, pi =
math.abs, math.cos, math.floor, math.sin, math.sqrt, math.pi
------------------------------------------------------------------------------
--
-- Helper functions
--
local node_ok = function(pos, fallback)
fallback = fallback or mobs.fallback_node
local node = minetest.get_node_or_nil(pos)
@ -46,6 +48,7 @@ end
local function get_sign(i)
i = i or 0
if i == 0 then
@ -57,6 +60,7 @@ end
local function get_velocity(v, yaw, y)
local x = -sin(yaw) * v
local z = cos(yaw) * v
@ -71,6 +75,8 @@ end
local function force_detach(player)
if not player then return end
local attached_to = player:get_attach()
if not attached_to then
@ -85,19 +91,27 @@ local function force_detach(player)
end
player:set_detach()
player_api.player_attached[player:get_player_name()] = false
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player_api.set_animation(player, "stand", 30)
player:set_properties({visual_size = {x = 1, y = 1}})
local name = player:get_player_name()
if is_50 then
player_api.player_attached[name] = false
player_api.set_animation(player, "stand", 30)
else
default.player_attached[name] = false
default.player_set_animation(player, "stand", 30)
end
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_properties({visual_size = {x = 1, y = 1}})
end
-------------------------------------------------------------------------------
minetest.register_on_leaveplayer(function(player)
force_detach(player)
end)
minetest.register_on_shutdown(function()
local players = minetest.get_connected_players()
@ -107,12 +121,12 @@ minetest.register_on_shutdown(function()
end
end)
minetest.register_on_dieplayer(function(player)
force_detach(player)
return true
end)
-------------------------------------------------------------------------------
-- Just for correct detaching
local function find_free_pos(pos)
@ -147,7 +161,6 @@ local function find_free_pos(pos)
return pos
end
-------------------------------------------------------------------------------
function mobs.attach(entity, player)
@ -169,8 +182,13 @@ function mobs.attach(entity, player)
force_detach(player)
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
if is_50 then
player_api.player_attached[player:get_player_name()] = true
else
default.player_attached[player:get_player_name()] = true
end
player:set_attach(entity.object, "", attach_at, entity.player_rotation)
player:set_eye_offset(eye_offset, {x = 0, y = 0, z = 0})
player:set_properties({
@ -183,7 +201,12 @@ function mobs.attach(entity, player)
minetest.after(0.2, function()
if player and player:is_player() then
if is_50 then
player_api.set_animation(player, "sit", 30)
else
default.player_set_animation(player, "sit", 30)
end
end
end)
@ -192,6 +215,7 @@ end
function mobs.detach(player)
force_detach(player)
minetest.after(0.1, function()
@ -218,7 +242,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end
local acce_y = 0
local velo = entity.object:get_velocity()
local velo = entity.object:get_velocity() ; if not velo then return end
entity.v = get_v(velo) * get_sign(entity.v)
@ -230,7 +254,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- move forwards
if ctrl.up then
entity.v = entity.v + entity.accel / 10
entity.v = entity.v + entity.accel * dtime
-- move backwards
elseif ctrl.down then
@ -239,7 +263,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
return
end
entity.v = entity.v - entity.accel / 10
entity.v = entity.v - entity.accel * dtime
end
-- mob rotation
@ -262,6 +286,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
entity.object:set_yaw(horz - entity.rotate)
if can_fly then
-- fly up
if ctrl.jump then
@ -271,7 +296,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
elseif velo.y > 0 then
velo.y = velo.y - 0.1
velo.y = velo.y - dtime
if velo.y < 0 then velo.y = 0 end
end
@ -285,7 +310,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
elseif velo.y < 0 then
velo.y = velo.y + 0.1
velo.y = velo.y + dtime
if velo.y > 0 then velo.y = 0 end
end
@ -330,14 +355,10 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end
-- enforce speed limit forward and reverse
local max_spd = entity.max_speed_reverse
if get_sign(entity.v) >= 0 then
max_spd = entity.max_speed_forward
end
if abs(entity.v) > max_spd then
entity.v = entity.v - get_sign(entity.v)
if entity.v > entity.max_speed_forward then
entity.v = entity.max_speed_forward
elseif entity.v < -entity.max_speed_reverse then
entity.v = -entity.max_speed_reverse
end
-- Set position, velocity and acceleration
@ -345,7 +366,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
if not p then return end
local new_acce = {x = 0, y = -9.81, z = 0}
local new_acce = {x = 0, y = entity.fall_speed, z = 0}
p.y = p.y - 0.5
@ -427,14 +448,15 @@ end
-- directional flying routine by D00Med (edited by TenPlus1)
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
local ctrl = entity.driver:get_player_control()
local ctrl = entity.driver:get_player_control() ; if not ctrl then return end
local velo = entity.object:get_velocity()
local dir = entity.driver:get_look_dir()
local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
local yaw = entity.driver:get_look_horizontal() + 1.57
if not ctrl or not velo then return end
if not ctrl or not velo then return end
if ctrl.up then
entity.object:set_velocity({
x = dir.x * speed,
y = dir.y * speed + 2,