Compare commits
11 Commits
c02fdfe5f0
...
8ddc921789
Author | SHA1 | Date | |
---|---|---|---|
8ddc921789 | |||
7771da2e0a | |||
910a46b16d | |||
e4623dec52 | |||
d76d2d307a | |||
4bf2555144 | |||
c876bb63c7 | |||
0a86398377 | |||
320ca97164 | |||
cbfe800342 | |||
f0fe65ec50 |
127
api.lua
127
api.lua
@ -33,7 +33,7 @@ local use_mc2 = minetest.get_modpath("mcl_core")
|
|||||||
-- Global
|
-- Global
|
||||||
mobs = {
|
mobs = {
|
||||||
mod = "redo",
|
mod = "redo",
|
||||||
version = "20230927",
|
version = "20231106",
|
||||||
translate = S, intllib = S,
|
translate = S, intllib = S,
|
||||||
invis = minetest.global_exists("invisibility") and invisibility or {},
|
invis = minetest.global_exists("invisibility") and invisibility or {},
|
||||||
node_ice = "default:ice",
|
node_ice = "default:ice",
|
||||||
@ -114,7 +114,8 @@ local pathfinder_enable = settings:get_bool("mob_pathfinder_enable") or true
|
|||||||
local pathfinding_stuck_timeout = tonumber(
|
local pathfinding_stuck_timeout = tonumber(
|
||||||
settings:get("mob_pathfinding_stuck_timeout")) or 3.0
|
settings:get("mob_pathfinding_stuck_timeout")) or 3.0
|
||||||
-- how long will mob follow path before giving up
|
-- how long will mob follow path before giving up
|
||||||
local pathfinding_stuck_path_timeout = tonumber(settings:get("mob_pathfinding_stuck_path_timeout")) or 5.0
|
local pathfinding_stuck_path_timeout = tonumber(
|
||||||
|
settings:get("mob_pathfinding_stuck_path_timeout")) or 5.0
|
||||||
-- which algorithm to use, Dijkstra(default) or A*_noprefetch or A*
|
-- which algorithm to use, Dijkstra(default) or A*_noprefetch or A*
|
||||||
-- fix settings not allowing "*"
|
-- fix settings not allowing "*"
|
||||||
local pathfinding_algorithm = settings:get("mob_pathfinding_algorithm") or "Dijkstra"
|
local pathfinding_algorithm = settings:get("mob_pathfinding_algorithm") or "Dijkstra"
|
||||||
@ -182,6 +183,7 @@ mobs.mob_class = {
|
|||||||
walk_chance = 50,
|
walk_chance = 50,
|
||||||
stand_chance = 30,
|
stand_chance = 30,
|
||||||
attack_chance = 5,
|
attack_chance = 5,
|
||||||
|
attack_patience = 11
|
||||||
passive = false,
|
passive = false,
|
||||||
blood_amount = 5,
|
blood_amount = 5,
|
||||||
blood_texture = "mobs_blood.png",
|
blood_texture = "mobs_blood.png",
|
||||||
@ -217,6 +219,7 @@ mobs.mob_class = {
|
|||||||
friendly_fire = true,
|
friendly_fire = true,
|
||||||
facing_fence = false,
|
facing_fence = false,
|
||||||
_breed_countdown = nil,
|
_breed_countdown = nil,
|
||||||
|
_tame_countdown = nil,
|
||||||
_cmi_is_mob = true
|
_cmi_is_mob = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +230,7 @@ local mob_class_meta = {__index = mob_class}
|
|||||||
-- play sound
|
-- play sound
|
||||||
function mob_class:mob_sound(sound)
|
function mob_class:mob_sound(sound)
|
||||||
|
|
||||||
if sound then
|
if not sound then return end
|
||||||
|
|
||||||
-- higher pitch for a child
|
-- higher pitch for a child
|
||||||
local pitch = self.child and 1.5 or 1.0
|
local pitch = self.child and 1.5 or 1.0
|
||||||
@ -238,11 +241,10 @@ function mob_class:mob_sound(sound)
|
|||||||
minetest.sound_play(sound, {
|
minetest.sound_play(sound, {
|
||||||
object = self.object,
|
object = self.object,
|
||||||
gain = 1.0,
|
gain = 1.0,
|
||||||
max_hear_distance = self.sounds.distance,
|
max_hear_distance = (self.sounds and self.sounds.distance) or 10,
|
||||||
pitch = pitch
|
pitch = pitch
|
||||||
}, true)
|
}, true)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- attack player/mob
|
-- attack player/mob
|
||||||
@ -832,6 +834,8 @@ function mob_class:update_tag()
|
|||||||
text = "\nLoving: " .. (self.hornytimer - (HORNY_TIME + HORNY_AGAIN_TIME))
|
text = "\nLoving: " .. (self.hornytimer - (HORNY_TIME + HORNY_AGAIN_TIME))
|
||||||
elseif self.child == true then
|
elseif self.child == true then
|
||||||
text = "\nGrowing: " .. (self.hornytimer - CHILD_GROW_TIME)
|
text = "\nGrowing: " .. (self.hornytimer - CHILD_GROW_TIME)
|
||||||
|
elseif self._tame_countdown then
|
||||||
|
text = "\nTaming: " .. self._tame_countdown
|
||||||
elseif self._breed_countdown then
|
elseif self._breed_countdown then
|
||||||
text = "\nBreeding: " .. self._breed_countdown
|
text = "\nBreeding: " .. self._breed_countdown
|
||||||
end
|
end
|
||||||
@ -1856,7 +1860,9 @@ function mob_class:smart_mobs(s, p, dist, dtime)
|
|||||||
s.y = sground.y + 1
|
s.y = sground.y + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local p1 = self.attack:get_pos()
|
local p1 = self.attack and self.attack:get_pos()
|
||||||
|
|
||||||
|
if not p1 then return end
|
||||||
|
|
||||||
p1.x = floor(p1.x + 0.5)
|
p1.x = floor(p1.x + 0.5)
|
||||||
p1.y = floor(p1.y + 0.5)
|
p1.y = floor(p1.y + 0.5)
|
||||||
@ -2000,8 +2006,7 @@ local function is_peaceful_player(player)
|
|||||||
local player_name = player:get_player_name()
|
local player_name = player:get_player_name()
|
||||||
|
|
||||||
-- player priv enabled
|
-- player priv enabled
|
||||||
if player_name
|
if player_name and minetest.check_player_privs(player_name, "peaceful_player") then
|
||||||
and minetest.check_player_privs(player_name, "peaceful_player") then
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -2337,6 +2342,21 @@ function mob_class:dogswitch(dtime)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- stop attack
|
||||||
|
function mob_class:stop_attack()
|
||||||
|
|
||||||
|
self.attack = nil
|
||||||
|
self.following = nil
|
||||||
|
self.v_start = false
|
||||||
|
self.timer = 0
|
||||||
|
self.blinktimer = 0
|
||||||
|
self.path.way = nil
|
||||||
|
self:set_velocity(0)
|
||||||
|
self.state = "stand"
|
||||||
|
self:set_animation("stand", true)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- execute current state (stand, walk, run, attacks)
|
-- execute current state (stand, walk, run, attacks)
|
||||||
function mob_class:do_states(dtime)
|
function mob_class:do_states(dtime)
|
||||||
|
|
||||||
@ -2515,19 +2535,28 @@ function mob_class:do_states(dtime)
|
|||||||
|
|
||||||
--print(" ** stop attacking **", self.name, self.health, dist, self.view_range)
|
--print(" ** stop attacking **", self.name, self.health, dist, self.view_range)
|
||||||
|
|
||||||
self.attack = nil
|
self:stop_attack()
|
||||||
self.following = nil
|
|
||||||
self.v_start = false
|
|
||||||
self.timer = 0
|
|
||||||
self.blinktimer = 0
|
|
||||||
self.path.way = nil
|
|
||||||
self:set_velocity(0)
|
|
||||||
self.state = "stand"
|
|
||||||
self:set_animation("stand", true)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- check enemy is in sight
|
||||||
|
local in_sight = self:line_of_sight(
|
||||||
|
{x = s.x, y = s.y + 0.5, z = s.z},
|
||||||
|
{x = p.x, y = p.y + 0.5, z = p.z})
|
||||||
|
|
||||||
|
-- stop attacking when enemy not seen for 11 seconds
|
||||||
|
if not in_sight then
|
||||||
|
|
||||||
|
self.target_time_lost = (self.target_time_lost or 0) + dtime
|
||||||
|
|
||||||
|
if self.target_time_lost > self.attack_patience then
|
||||||
|
self:stop_attack()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.target_time_lost = 0
|
||||||
|
end
|
||||||
|
|
||||||
if self.attack_type == "explode" then
|
if self.attack_type == "explode" then
|
||||||
|
|
||||||
yaw_to_pos(self, p)
|
yaw_to_pos(self, p)
|
||||||
@ -2542,7 +2571,7 @@ function mob_class:do_states(dtime)
|
|||||||
-- start timer when in reach and line of sight
|
-- start timer when in reach and line of sight
|
||||||
if not self.v_start
|
if not self.v_start
|
||||||
and dist <= self.reach
|
and dist <= self.reach
|
||||||
and self:line_of_sight(s, p, 2) then
|
and in_sight then
|
||||||
|
|
||||||
self.v_start = true
|
self.v_start = true
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
@ -2554,7 +2583,7 @@ function mob_class:do_states(dtime)
|
|||||||
-- stop timer if out of reach or direct line of sight
|
-- stop timer if out of reach or direct line of sight
|
||||||
elseif self.allow_fuse_reset
|
elseif self.allow_fuse_reset
|
||||||
and self.v_start
|
and self.v_start
|
||||||
and (dist > self.reach or not self:line_of_sight(s, p, 2)) then
|
and (dist > self.reach or not in_sight) then
|
||||||
|
|
||||||
--print("=== explosion timer stopped")
|
--print("=== explosion timer stopped")
|
||||||
|
|
||||||
@ -2588,10 +2617,8 @@ function mob_class:do_states(dtime)
|
|||||||
self.blinktimer = 0
|
self.blinktimer = 0
|
||||||
|
|
||||||
if self.blinkstatus then
|
if self.blinkstatus then
|
||||||
|
|
||||||
self.object:set_texture_mod(self.texture_mods)
|
self.object:set_texture_mod(self.texture_mods)
|
||||||
else
|
else
|
||||||
|
|
||||||
self.object:set_texture_mod(self.texture_mods .. "^[brighten")
|
self.object:set_texture_mod(self.texture_mods .. "^[brighten")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -2604,10 +2631,9 @@ function mob_class:do_states(dtime)
|
|||||||
|
|
||||||
local pos = self.object:get_pos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
-- dont damage anything if area protected or next to waterpathfinding_max_jump
|
-- dont damage anything if area protected or next to water
|
||||||
if minetest.find_node_near(pos, 1, {"group:water"})
|
if minetest.find_node_near(pos, 1, {"group:water"})
|
||||||
or minetest.is_protected(pos, "") then
|
or minetest.is_protected(pos, "") then
|
||||||
|
|
||||||
node_break_radius = 1
|
node_break_radius = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -3238,6 +3264,28 @@ function mob_class:mob_staticdata()
|
|||||||
self.serialized_cmi_components = cmi.serialize_components(self._cmi_components)
|
self.serialized_cmi_components = cmi.serialize_components(self._cmi_components)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- move existing variables to new table for future compatibility
|
||||||
|
-- using self.initial_properties lost some variables when backing up?!?
|
||||||
|
if not self.backup_properties then
|
||||||
|
|
||||||
|
self.backup_properties = {
|
||||||
|
hp_max = self.hp_max,
|
||||||
|
physical = self.physical,
|
||||||
|
collisionbox = self.collisionbox,
|
||||||
|
selectionbox = self.selectionbox,
|
||||||
|
visual = self.visual,
|
||||||
|
visual_size = self.visual_size,
|
||||||
|
mesh = self.mesh,
|
||||||
|
textures = self.textures,
|
||||||
|
make_footstep_sound = self.make_footstep_sound,
|
||||||
|
stepheight = self.stepheight,
|
||||||
|
glow = self.glow,
|
||||||
|
nametag = self.nametag,
|
||||||
|
damage_texture_modifier = self.damage_texture_modifier,
|
||||||
|
infotext = self.infotext
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
return minetest.serialize(clean_staticdata(self))
|
return minetest.serialize(clean_staticdata(self))
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -3525,7 +3573,7 @@ function mob_class:on_step(dtime, moveresult)
|
|||||||
-- check and stop if standing at cliff and fear of heights
|
-- check and stop if standing at cliff and fear of heights
|
||||||
self.at_cliff = self:is_at_cliff()
|
self.at_cliff = self:is_at_cliff()
|
||||||
|
|
||||||
if self.pause_timer <= 0 and self.at_cliff then
|
if self.pause_timer < 0 and self.at_cliff then
|
||||||
self:set_velocity(0)
|
self:set_velocity(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -3682,7 +3730,7 @@ function mobs:register_mob(name, def)
|
|||||||
|
|
||||||
minetest.register_entity(name, setmetatable({
|
minetest.register_entity(name, setmetatable({
|
||||||
|
|
||||||
stepheight = def.stepheight,
|
stepheight = def.stepheight or 1.1,
|
||||||
name = (name:find(":") and name or ":"..name),
|
name = (name:find(":") and name or ":"..name),
|
||||||
type = def.type,
|
type = def.type,
|
||||||
attack_type = def.attack_type,
|
attack_type = def.attack_type,
|
||||||
@ -3737,6 +3785,7 @@ minetest.register_entity(name, setmetatable({
|
|||||||
walk_chance = def.walk_chance,
|
walk_chance = def.walk_chance,
|
||||||
stand_chance = def.stand_chance,
|
stand_chance = def.stand_chance,
|
||||||
attack_chance = def.attack_chance,
|
attack_chance = def.attack_chance,
|
||||||
|
attack_patience = def.attack_patience,
|
||||||
passive = def.passive,
|
passive = def.passive,
|
||||||
knock_back = def.knock_back,
|
knock_back = def.knock_back,
|
||||||
blood_amount = def.blood_amount,
|
blood_amount = def.blood_amount,
|
||||||
@ -4040,7 +4089,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
pos, node, active_object_count, active_object_count_wider)
|
pos, node, active_object_count, active_object_count_wider)
|
||||||
|
|
||||||
-- use instead of abm's chance setting when using lbm
|
-- use instead of abm's chance setting when using lbm
|
||||||
if map_load and random(max(1, (chance * mob_chance_multiplier))) > 1 then
|
if map_load and random(max(1, (chance * mob_chance_multiplier/10))) > 1 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -4172,14 +4221,16 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
|
|
||||||
local mob = minetest.add_entity(pos, name)
|
local mob = minetest.add_entity(pos, name)
|
||||||
|
|
||||||
-- print("[mobs] Spawned " .. name .. " at "
|
|
||||||
-- .. minetest.pos_to_string(pos) .. " on "
|
|
||||||
-- .. node.name .. " near " .. neighbors[1])
|
|
||||||
|
|
||||||
if mob_log_spawn then
|
if mob_log_spawn then
|
||||||
|
|
||||||
minetest.log("[MOBS] Spawned " .. name .. " at "
|
local pos_string = pos and minetest.pos_to_string(pos) or ""
|
||||||
.. minetest.pos_to_string(pos))
|
|
||||||
|
minetest.log(
|
||||||
|
"[MOBS] Spawned "
|
||||||
|
.. (name or "")
|
||||||
|
.. " at "
|
||||||
|
.. pos_string
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
if on_spawn and mob then
|
if on_spawn and mob then
|
||||||
@ -4210,7 +4261,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
|
|||||||
nodenames = nodes,
|
nodenames = nodes,
|
||||||
neighbors = neighbors,
|
neighbors = neighbors,
|
||||||
interval = interval,
|
interval = interval,
|
||||||
chance = max(1, (chance * mob_chance_multiplier)),
|
chance = max(1, (chance * (mob_chance_multiplier/10))),
|
||||||
catch_up = false,
|
catch_up = false,
|
||||||
|
|
||||||
action = function(pos, node, active_object_count, active_object_count_wider)
|
action = function(pos, node, active_object_count, active_object_count_wider)
|
||||||
@ -4426,7 +4477,6 @@ end
|
|||||||
|
|
||||||
|
|
||||||
-- Register spawn eggs
|
-- Register spawn eggs
|
||||||
|
|
||||||
-- Note: This also introduces the “spawn_egg” group:
|
-- Note: This also introduces the “spawn_egg” group:
|
||||||
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
|
-- * spawn_egg=1: Spawn egg (generic mob, no metadata)
|
||||||
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
|
-- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata)
|
||||||
@ -4777,7 +4827,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
|||||||
if self.child == true then
|
if self.child == true then
|
||||||
|
|
||||||
-- deduct 10% of the time to adulthood
|
-- deduct 10% of the time to adulthood
|
||||||
self.hornytimer = math.floor(self.hornytimer + (
|
self.hornytimer = floor(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
|
||||||
@ -4785,7 +4835,8 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
|||||||
|
|
||||||
-- feed and tame
|
-- feed and tame
|
||||||
self.food = (self.food or 0) + 1
|
self.food = (self.food or 0) + 1
|
||||||
self._breed_countdown = feed_count - self.food
|
self._breed_countdown = breed and (feed_count - self.food)
|
||||||
|
self._tame_countdown = not self.tamed and tame and (feed_count - self.food)
|
||||||
|
|
||||||
if self.food >= feed_count then
|
if self.food >= feed_count then
|
||||||
|
|
||||||
@ -4915,10 +4966,10 @@ function mobs:alias_mob(old_name, new_name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- spawn egg
|
-- spawn egg
|
||||||
minetest.register_alias(old_name, new_name)
|
minetest.register_alias( (old_name:find(":") and old_name or ":"..old_name), new_name)
|
||||||
|
|
||||||
-- entity
|
-- entity
|
||||||
minetest.register_entity( (old_name:find(":") and old_name or ":"..old_name) , {
|
minetest.register_entity( ":"..old_name , {
|
||||||
|
|
||||||
physical = false, static_save = false,
|
physical = false, static_save = false,
|
||||||
|
|
||||||
|
11
api.txt
11
api.txt
@ -104,6 +104,8 @@ functions needed for the mob to work properly which contains the following:
|
|||||||
hours and only attacking player at night or when
|
hours and only attacking player at night or when
|
||||||
provoked.
|
provoked.
|
||||||
'attack_chance' 0 to 100 chance the mob will attack (default is 5).
|
'attack_chance' 0 to 100 chance the mob will attack (default is 5).
|
||||||
|
'attack_patience' Time in seconds before mob gives up attacking if
|
||||||
|
player isn't seen (Defaults to 11).
|
||||||
'attack_monsters' when true mob will attack monsters.
|
'attack_monsters' when true mob will attack monsters.
|
||||||
'attack_animals' when true mob will attack animals.
|
'attack_animals' when true mob will attack animals.
|
||||||
'attack_npcs' when true mob will attack npcs within range.
|
'attack_npcs' when true mob will attack npcs within range.
|
||||||
@ -387,6 +389,15 @@ for each mob.
|
|||||||
in it's name.
|
in it's name.
|
||||||
|
|
||||||
|
|
||||||
|
Internal Functions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Each mob contains a set of functions that can be called for use internally or from
|
||||||
|
another mod entirely, replace mob_class with the mob entity variable:
|
||||||
|
|
||||||
|
mob_class:stop_attack() -- stops mob attacking
|
||||||
|
|
||||||
|
|
||||||
Adding Mobs in World
|
Adding Mobs in World
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -242,6 +242,7 @@ function mobs.attach(entity, player)
|
|||||||
default.player_set_animation(player, "sit", 30)
|
default.player_set_animation(player, "sit", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
||||||
|
@ -4,7 +4,7 @@ MOBS REDO for MINETEST
|
|||||||
This mod contains the API only for adding your own mobs into the world, so
|
This mod contains the API only for adding your own mobs into the world, so
|
||||||
please use the additional modpacks to add animals, monsters, and npcs.
|
please use the additional modpacks to add animals, monsters, and npcs.
|
||||||
|
|
||||||
https://forum.minetest.net/viewtopic.php?f=11&t=9917
|
https://codeberg.org/minenux/minetest-mod-mobs_redo
|
||||||
|
|
||||||
Information
|
Information
|
||||||
-----------
|
-----------
|
||||||
@ -12,6 +12,10 @@ Information
|
|||||||
Built from PilzAdam's original Simple Mobs with additional mobs by KrupnoPavel,
|
Built from PilzAdam's original Simple Mobs with additional mobs by KrupnoPavel,
|
||||||
Zeg9, ExeterDad and AspireMint.
|
Zeg9, ExeterDad and AspireMint.
|
||||||
|
|
||||||
|
This mod is special one already compatible with older engines.. with backported
|
||||||
|
patches to work both in multicraft, minetest, mineclone and finetest, becouse
|
||||||
|
the tenplus1 only works in last minetest, admins will not wants to constant upgrades!
|
||||||
|
|
||||||
## Crafts
|
## Crafts
|
||||||
|
|
||||||
- **Nametag**. Can be crafted by paper, black dye, and string. Can be used
|
- **Nametag**. Can be crafted by paper, black dye, and string. Can be used
|
||||||
|
Loading…
x
Reference in New Issue
Block a user