Mods update

master
daretmavi 2021-02-13 16:30:02 +01:00
parent ca2b25e053
commit 80d1a6c21f
254 changed files with 5232 additions and 529 deletions

View File

@ -112,11 +112,11 @@ origin https://github.com/TheTermos/mobkit (fetch)
Mod: lib_api/mobkit
origin https://notabug.org/tenplus1/mobs_redo (fetch)
* master c158e84 [origin/master] stop grown child mobs sinking into blocks below
* master 11e1d52 [origin/master] replace minetest 5.0 check
Mod: lib_api/mobs_redo
origin https://github.com/appgurueu/modlib (fetch)
* master b9483fb [origin/master] Add objects_inside_- radius and area iterators
* master ba4a6ab [origin/master] b3d test default false
Mod: lib_api/modlib
origin git@github.com:runsy/rcbows.git (fetch)
@ -128,7 +128,7 @@ origin git@github.com:minetest-mods/ts_workshop.git (fetch)
Mod: lib_api/ts_workshop
origin https://github.com/Skandarella/Animal-World.git (fetch)
* main 75dfe53 [origin/main] Delete test.txt
* main f45ee6f [origin/main] Add files via upload
Mod: mobs/mobs_mobs/Animal-World
origin https://github.com/FreeLikeGNU/goblins.git (fetch)
@ -152,15 +152,15 @@ origin https://github.com/berengma/aerotest (fetch)
Mod: mobs/mobs_mobkit/aerotest
origin https://github.com/runsy/petz (fetch)
* master 2080c8f [origin/master] pony cimarron
* master 84e8b8f [origin/master] frogs improved
Mod: mobs/mobs_mobkit/petz
origin https://github.com/berengma/water_life (fetch)
* master 17c4289 [origin/master] Merge pull request #69 from berengma/staticIsTrue
* master 6b4ad15 [origin/master] Merge pull request #72 from berengma/dev
Mod: mobs/mobs_mobkit/water_life
origin https://github.com/minetest-mods/3d_armor (fetch)
* master e7abacc [origin/master] Add armor set and armor set bonus setting (#41)
* master 42f7dac [origin/master] Update fire and water protection (#42)
Mod: player/3d_armor
origin https://github.com/appgurueu/character_anim (fetch)
@ -191,8 +191,12 @@ origin https://github.com/minetest-mods/wielded_light.git (fetch)
* master 60b31d3 [origin/master] fix mt-5.4 compatibility Closes #7
Mod: player/wielded_light
origin https://notabug.org/TenPlus1/bonemeal.git (fetch)
* master 308baf3 [origin/master] update mod.conf info
Mod: tools/bonemeal
origin git@gitlab.com:daretmavi/bucket-lite.git (fetch)
* master 03a1ebf [origin/master] Merge branch 'devel' into 'master'
* master 5075acb [origin/master] Merge branch 'devel' into 'master'
Mod: tools/bucket-lite
origin git@github.com:runsy/farbows.git (fetch)

View File

@ -8,7 +8,7 @@ local use_cmi = minetest.global_exists("cmi")
mobs = {
mod = "redo",
version = "20210203",
version = "20210206",
intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {}
}
@ -539,12 +539,10 @@ local ray_line_of_sight = function(self, pos1, pos2)
return true
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)
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)
end

378
mods/lib_api/modlib/b3d.lua Normal file
View File

@ -0,0 +1,378 @@
local metatable = {__index = getfenv(1)}
--! experimental
--+ Reads a single BB3D chunk from a stream
--+ Doing `assert(stream:read(1) == nil)` afterwards is recommended
--+ See `b3d_specification.txt` as well as https://github.com/blitz-research/blitz3d/blob/master/blitz3d/loader_b3d.cpp
--> B3D model
function read(stream)
local left = 8
local function byte()
left = left - 1
return assert(stream:read(1):byte())
end
local function int()
local value = byte() + byte() * 0x100 + byte() * 0x10000 + byte() * 0x1000000
if value >= 2^31 then
return value - 2^32
end
return value
end
local function id()
return int() + 1
end
local function optional_id()
local id = int()
if id == -1 then
return
end
return id + 1
end
local function string()
local rope = {}
while true do
left = left - 1
local char = assert(stream:read(1))
if char == "\0" then
return table.concat(rope)
end
table.insert(rope, char)
end
end
local function float()
-- TODO properly truncate to single floating point
local byte_4, byte_3, byte_2, byte_1 = byte(), byte(), byte(), byte()
local sign = 1
if byte_1 >= 0x80 then
sign = -1
byte_1 = byte_1 - 0x80
end
local exponent = byte_1 * 2
if byte_2 >= 0x80 then
byte_2 = byte_2 - 0x80
exponent = exponent + 1
end
local mantissa = ((((byte_4 / 0x100) + byte_3) / 0x100) + byte_2) / 0x80
if exponent == 0xFF then
if mantissa == 0 then
return sign * math.huge
end
-- TODO differentiate quiet and signalling NaN as well as positive and negative
return 0/0
end
if exponent == 0 then
-- subnormal value
return sign * 2^-126 * mantissa
end
return sign * 2 ^ (exponent - 127) * (1 + mantissa)
end
local function float_array(length)
local list = {}
for index = 1, length do
list[index] = float()
end
return list
end
local function color()
return {
r = float(),
g = float(),
b = float(),
a = float()
}
end
local function vector3()
return float_array(3)
end
local function quaternion()
return {[4] = float(), [1] = float(), [2] = float(), [3] = float()}
end
local function content()
assert(left >= 0, stream:seek())
return left ~= 0
end
local chunk
local chunks = {
TEXS = function()
local textures = {}
while content() do
table.insert(textures, {
file = string(),
flags = int(),
blend = int(),
pos = float_array(2),
scale = float_array(2),
rotation = float()
})
end
return textures
end,
BRUS = function()
local brushes = {}
brushes.n_texs = int()
assert(brushes.n_texs <= 8)
while content() do
local brush = {
name = string(),
color = color(),
shininess = float(),
blend = float(),
fx = float(),
texture_id = {}
}
for index = 1, brushes.n_texs do
brush.texture_id[index] = optional_id()
end
table.insert(brushes, brush)
end
return brushes
end,
VRTS = function()
local vertices = {
flags = int(),
tex_coord_sets = int(),
tex_coord_set_size = int()
}
assert(vertices.tex_coord_sets <= 8 and vertices.tex_coord_set_size <= 4)
local has_normal = (vertices.flags % 2 == 1) or nil
local has_color = (math.floor(vertices.flags / 2) % 2 == 1) or nil
while content() do
local vertex = {
pos = vector3(),
normal = has_normal and vector3(),
color = has_color and color(),
tex_coords = {}
}
for tex_coord_set = 1, vertices.tex_coord_sets do
local tex_coords = {}
for tex_coord = 1, vertices.tex_coord_set_size do
tex_coords[tex_coord] = float()
end
vertex.tex_coords[tex_coord_set] = tex_coords
end
table.insert(vertices, vertex)
end
return vertices
end,
TRIS = function()
local tris = {
brush_id = id(),
vertex_ids = {}
}
while content() do
table.insert(tris.vertex_ids, {id(), id(), id()})
end
return tris
end,
MESH = function()
local mesh = {
brush_id = optional_id(),
vertices = chunk{VRTS = true}
}
mesh.triangle_sets = {}
repeat
local tris = chunk{TRIS = true}
table.insert(mesh.triangle_sets, tris)
until not content()
return mesh
end,
BONE = function()
local bone = {}
while content() do
local vertex_id = id()
assert(not bone[vertex_id], "duplicate vertex weight")
local weight = float()
if weight > 0 then
-- Many exporters include unneeded zero weights
bone[vertex_id] = weight
end
end
return bone
end,
KEYS = function()
local flags = int()
local _flags = flags % 8
local rotation, scale, position
if _flags >= 4 then
rotation = true
_flags = _flags - 4
end
if _flags >= 2 then
scale = true
_flags = _flags - 2
end
position = _flags >= 1
local bone = {
flags = flags
}
while content() do
table.insert(bone, {
frame = int(),
position = position and vector3() or nil,
scale = scale and vector3() or nil,
rotation = rotation and quaternion() or nil
})
end
-- Ensure frames are sorted ascending
table.sort(bone, function(a, b) return a.frame < b.frame end)
return bone
end,
ANIM = function()
return {
-- flags are unused
flags = int(),
frames = int(),
fps = float()
}
end,
NODE = function()
local node = {
name = string(),
position = vector3(),
scale = vector3(),
keys = {},
rotation = quaternion(),
children = {}
}
local node_type
-- See https://github.com/blitz-research/blitz3d/blob/master/blitz3d/loader_b3d.cpp#L263
-- Order is not validated; double occurences of mutually exclusive node def are
while content() do
local elem, type = chunk()
if type == "MESH" then
assert(not node_type)
node_type = "mesh"
node.mesh = elem
elseif type == "BONE" then
assert(not node_type)
node_type = "bone"
node.bone = elem
elseif type == "KEYS" then
assert((node.keys[#node.keys] or {}).frame ~= (elem[1] or {}).frame, "duplicate frame")
modlib.table.append(node.keys, elem)
elseif type == "NODE" then
table.insert(node.children, elem)
elseif type == "ANIM" then
node.animation = elem
else
assert(not node_type)
node_type = "pivot"
end
end
-- TODO somehow merge keys
return node
end,
BB3D = function()
local version = int()
local self = {
version = {
major = math.floor(version / 100),
minor = version % 100,
raw = version
},
textures = {},
brushes = {}
}
assert(self.version.major <= 2, "unsupported version: " .. self.version.major)
while content() do
local field, type = chunk{TEXS = true, BRUS = true, NODE = true}
if type == "TEXS" then
modlib.table.append(self.textures, field)
elseif type == "BRUS" then
modlib.table.append(self.brushes, field)
else
self.node = field
end
end
return self
end
}
local function chunk_header()
left = left - 4
return stream:read(4), int()
end
function chunk(possible_chunks)
local type, new_left = chunk_header()
local parent_left
left, parent_left = new_left, left
if possible_chunks and not possible_chunks[type] then
error("expected one of " .. table.concat(modlib.table.keys(possible_chunks), ", ") .. ", found " .. type)
end
local res = assert(chunks[type])()
assert(left == 0)
left = parent_left - new_left
return res, type
end
local self = chunk{BB3D = true}
return setmetatable(self, metatable)
end
-- TODO function write(self, stream)
local binary_search_frame = modlib.table.binary_search_comparator(function(a, b)
return modlib.table.default_comparator(a, b.frame)
end)
--> [bonename] = { position = vector, rotation = quaternion, scale = vector }
function get_animated_bone_properties(self, keyframe, interpolate)
local function get_frame_values(keys)
local values = keys[keyframe]
if values and values.frame == keyframe then
return {
position = values.position,
rotation = values.rotation,
scale = values.scale
}
end
local index = binary_search_frame(keys, keyframe)
if index > 0 then
return keys[index]
end
index = -index
assert(index > 1 and index <= #keys)
local a, b = keys[index - 1], keys[index]
if not interpolate then
return a
end
local ratio = (keyframe - a.frame) / (b.frame - a.frame)
return {
position = (a.position and b.position and modlib.vector.interpolate(a.position, b.position, ratio)) or a.position or b.position,
rotation = (a.rotation and b.rotation and modlib.quaternion.interpolate(a.rotation, b.rotation, ratio)) or a.rotation or b.rotation,
scale = (a.scale and b.scale and modlib.vector.interpolate(a.scale, b.scale, ratio)) or a.scale or b.scale,
}
end
local bone_properties = {}
local function get_props(node)
local properties = {}
if node.keys and next(node.keys) ~= nil then
properties = modlib.table.add_all(properties, get_frame_values(node.keys))
end
for _, property in pairs{"position", "rotation", "scale"} do
properties[property] = properties[property] or modlib.table.copy(node[property])
end
if node.bone then
assert(not bone_properties[node.name])
bone_properties[node.name] = properties
end
for _, child in pairs(node.children or {}) do
get_props(child)
end
end
get_props(self.node)
return bone_properties
end

View File

@ -0,0 +1,260 @@
************************************************************************************
* Blitz3d file format V0.01 *
************************************************************************************
This document and the information contained within is placed in the Public Domain.
Please visit http://www.blitzbasic.co.nz for the latest version of this document.
Please contact marksibly@blitzbasic.co.nz for more information and general inquiries.
************************************************************************************
* Introduction *
************************************************************************************
The Blitz3D file format specifies a format for storing texture, brush and entity descriptions for
use with the Blitz3D programming language.
The rationale behind the creation of this format is to allow for the generation of much richer and
more complex Blitz3D scenes than is possible using established file formats - many of which do not
support key features of Blitz3D, and all of which miss out on at least some features!
A Blitz3D (.b3d) file is split up into a sequence of 'chunks', each of which can contain data
and/or other chunks.
Each chunk is preceded by an eight byte header:
char tag[4] ;4 byte chunk 'tag'
int length ;4 byte chunk length (not including *this* header!)
If a chunk contains both data and other chunks, the data always appears first and is of a fixed
length.
A file parser should ignore unrecognized chunks.
Blitz3D files are stored little endian (intel) style.
Many aspects of the file format are not quite a 'perfect fit' for the way Blitz3D works. This has
been done mainly to keep the file format simple, and to make life easier for the authors of third
party importers/exporters.
************************************************************************************
* Chunk Types *
************************************************************************************
This lists the types of chunks that can appear in a b3d file, and the data they contain.
Color values are always in the range 0 to 1.
string (char[]) values are 'C' style null terminated strings.
Quaternions are used to specify general orientations. The first value is the quaternion 'w' value,
the next 3 are the quaternion 'vector'. A 'null' rotation should be specified as 1,0,0,0.
Anything that is referenced 'by index' always appears EARLIER in the file than anything that
references it.
brush_id references can be -1: no brush.
In the following descriptions, {} is used to signify 'repeating until end of chunk'. Also, a chunk
name enclosed in '[]' signifies the chunk is optional.
Here we go!
BB3D
int version ;file format version: default=1
[TEXS] ;optional textures chunk
[BRUS] ;optional brushes chunk
[NODE] ;optional node chunk
The BB3D chunk appears first in a b3d file, and its length contains the rest of the file.
Version is in major*100+minor format. To check the version, just divide by 100 and compare it with
the major version your software supports, eg:
if file_version/100>my_version/100
RuntimeError "Can't handle this file version!"
EndIf
if file_version Mod 100>my_version Mod 100
;file is a more recent version, but should still be backwardly compatbile with what we can
handle!
EndIf
TEXS
{
char file[] ;texture file name
int flags,blend ;blitz3D TextureFLags and TextureBlend: default=1,2
float x_pos,y_pos ;x and y position of texture: default=0,0
float x_scale,y_scale ;x and y scale of texture: default=1,1
float rotation ;rotation of texture (in radians): default=0
}
The TEXS chunk contains a list of all textures used in the file.
The flags field value can conditional an additional flag value of '65536'. This is used to indicate that the texture uses secondary UV values, ala the TextureCoords command. Yes, I forgot about this one.
BRUS
int n_texs
{
char name[] ;eg "WATER" - just use texture name by default
float red,green,blue,alpha ;Blitz3D Brushcolor and Brushalpha: default=1,1,1,1
float shininess ;Blitz3D BrushShininess: default=0
int blend,fx ;Blitz3D Brushblend and BrushFX: default=1,0
int texture_id[n_texs] ;textures used in brush
}
The BRUS chunk contains a list of all brushes used in the file.
VRTS:
int flags ;1=normal values present, 2=rgba values present
int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8
int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4
{
float x,y,z ;always present
float nx,ny,nz ;vertex normal: present if (flags&1)
float red,green,blue,alpha ;vertex color: present if (flags&2)
float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
}
The VRTS chunk contains a list of vertices. The 'flags' value is used to indicate how much extra
data (normal/color) is stored with each vertex, and the tex_coord_sets and tex_coord_set_size
values describe texture coordinate information stored with each vertex.
TRIS:
int brush_id ;brush applied to these TRIs: default=-1
{
int vertex_id[3] ;vertex indices
}
The TRIS chunk contains a list of triangles that all share a common brush.
MESH:
int brush_id ;'master' brush: default=-1
VRTS ;vertices
TRIS[,TRIS...] ;1 or more sets of triangles
The MESH chunk describes a mesh. A mesh only has one VRTS chunk, but potentially many TRIS chunks.
BONE:
{
int vertex_id ;vertex affected by this bone
float weight ;how much the vertex is affected
}
The BONE chunk describes a bone. Weights are applied to the mesh described in the enclosing ANIM -
in 99% of cases, this will simply be the MESH contained in the root NODE chunk.
KEYS:
int flags ;1=position, 2=scale, 4=rotation
{
int frame ;where key occurs
float position[3] ;present if (flags&1)
float scale[3] ;present if (flags&2)
float rotation[4] ;present if (flags&4)
}
The KEYS chunk is a list of animation keys. The 'flags' value describes what kind of animation
info is stored in the chunk - position, scale, rotation, or any combination of.
ANIM:
int flags ;unused: default=0
int frames ;how many frames in anim
float fps ;default=60
The ANIM chunk describes an animation.
NODE:
char name[] ;name of node
float position[3] ;local...
float scale[3] ;coord...
float rotation[4] ;system...
[MESH|BONE] ;what 'kind' of node this is - if unrecognized, just use a Blitz3D
pivot.
[KEYS[,KEYS...]] ;optional animation keys
[NODE[,NODE...]] ;optional child nodes
[ANIM] ;optional animation
The NODE chunk describes a Blitz3D Entity. The scene hierarchy is expressed by the nesting of NODE
chunks.
NODE kinds are currently mutually exclusive - ie: a node can be a MESH, or a BONE, but not both!
However, it can be neither...if no kind is specified, the node is just a 'null' node - in Blitz3D
speak, a pivot.
The presence of an ANIM chunk in a NODE indicates that an animation starts here in the hierarchy.
This allows animations of differing speeds/lengths to be potentially nested.
There are many more 'kind' chunks coming, including camera, light, sprite, plane etc. For now, the
use of a Pivot in cases where the node kind is unknown will allow for backward compatibility.
************************************************************************************
* Examples *
************************************************************************************
A typical b3d file will contain 1 TEXS chunk, 1 BRUS chunk and 1 NODE chunk, like this:
BB3D
1
TEXS
...list of textures...
BRUS
...list of brushes...
NODE
...stuff in the node...
A simple, non-animating, non-textured etc mesh might look like this:
BB3D
1 ;version
NODE
"root_node" ;node name
0,0,0 ;position
1,1,1 ;scale
1,0,0,0 ;rotation
MESH ;the mesh
-1 ;brush: no brush
VRTS ;vertices in the mesh
0 ;no normal/color info in verts
0,0 ;no texture coords in verts
{x,y,z...} ;vertex coordinates
TRIS ;triangles in the mesh
-1 ;no brush for this triangle
{v0,v1,v2...} ;vertices
A more complex 'skinned mesh' might look like this (only chunks shown):
BB3D
TEXS ;texture list
BRUS ;brush list
NODE ;root node
MESH ;mesh - the 'skin'
ANIM ;anim
NODE ;first child of root node - eg: "pelvis"
BONE ;vertex weights for pelvis
KEYS ;anim keys for pelvis
NODE ;first child of pelvis - eg: "left-thigh"
BONE ;bone
KEYS ;anim keys for left-thigh
NODE ;second child of pelvis - eg: "right-thigh"
BONE ;vertex weights for right-thigh
KEYS ;anim keys for right-thigh
...and so on.

View File

@ -34,12 +34,24 @@ if _VERSION then
end
end
local function get_resource(modname, resource)
modlib = {
dir_delim = rawget(_G, "DIR_DELIM") or "/",
_RG = setmetatable({}, {
__index = function(_, index)
return rawget(_G, index)
end,
__newindex = function(_, index, value)
return rawset(_G, index, value)
end
})
}
local function get_resource(modname, resource, ...)
if not resource then
resource = modname
modname = minetest.get_current_modname()
end
return minetest.get_modpath(modname) .. "/" .. resource
return table.concat({minetest.get_modpath(modname), resource, ...}, modlib.dir_delim)
end
local function loadfile_exports(filename)
@ -50,15 +62,6 @@ local function loadfile_exports(filename)
return env
end
modlib = {_RG = setmetatable({}, {
__index = function(_, index)
return rawget(_G, index)
end,
__newindex = function(_, index, value)
return rawset(_G, index, value)
end
})}
for _, component in ipairs{
"mod",
"conf",
@ -72,10 +75,13 @@ for _, component in ipairs{
"table",
"text",
"vector",
"quaternion",
"minetest",
"trie",
"kdtree",
"heap",
"ranked_set"
"ranked_set",
"b3d"
} do
modlib[component] = loadfile_exports(get_resource(component .. ".lua"))
end

View File

@ -0,0 +1,54 @@
local metatable = {__index = getfenv(1)}
distance = modlib.vector.distance
--: vectors first vector is used to infer the dimension
--: distance (vector, other_vector) -> number, default: modlib.vector.distance
function new(vectors, distance)
assert(#vectors > 0, "vector list must not be empty")
local dimension = #vectors[1]
local function builder(vectors, axis)
if #vectors == 1 then return { value = vectors[1] } end
table.sort(vectors, function(a, b) return a[axis] > b[axis] end)
local median = math.floor(#vectors / 2)
local next_axis = ((axis + 1) % dimension) + 1
return setmetatable({
axis = axis,
pivot = vectors[median],
left = builder({ unpack(vectors, 1, median) }, next_axis),
right = builder({ unpack(vectors, median + 1) }, next_axis)
}, metatable)
end
local self = builder(vectors, 1)
self.distance = distance
return setmetatable(self, metatable)
end
function get_nearest_neighbor(self, vector)
local min_distance = math.huge
local nearest_neighbor
local distance_func = self.distance
local function visit(tree)
local axis = tree.axis
if tree.value ~= nil then
local distance = distance_func(tree.value, vector)
if distance < min_distance then
min_distance = distance
nearest_neighbor = tree.value
end
return
else
local this_side, other_side = tree.left, tree.right
if vector[axis] < tree.pivot[axis] then this_side, other_side = other_side, this_side end
visit(this_side)
if tree.pivot then
local dist = math.abs(tree.pivot[axis] - vector[axis])
if dist <= min_distance then visit(other_side) end
end
end
end
visit(self)
return nearest_neighbor, min_distance
end
-- TODO insertion & deletion + rebalancing

View File

@ -42,12 +42,13 @@ function init(modname)
extend(modname, "main")
end
--! deprecated
function extend_string(modname, string)
if not string then
string = modname
modname = minetest.get_current_modname()
end
include_env(string, _G[modname], true)
include_env(string, rawget(_G, modname), true)
end
function configuration(modname)

View File

@ -0,0 +1,129 @@
-- TODO OOP, extend vector
function from_euler_rotation(rotation)
rotation = vector.divide(rotation, 2)
local cos = vector.apply(rotation, math.cos)
local sin = vector.apply(rotation, math.sin)
return {
sin.z * cos.x * cos.y - cos.z * sin.x * sin.y,
cos.z * sin.x * cos.y + sin.z * cos.x * sin.y,
cos.z * cos.x * sin.y - sin.z * sin.x * cos.y,
cos.z * cos.x * cos.y + sin.z * sin.x * sin.y
}
end
function multiply(self, other)
return {
other[1] * self[1] - other[2] * self[2] - other[3] * self[3] - other[4] * self[4],
other[1] * self[2] + other[2] * self[1] - other[3] * self[4] + other[4] * self[3],
other[1] * self[3] + other[2] * self[4] + other[3] * self[1] - other[4] * self[2],
other[1] * self[4] - other[2] * self[3] + other[3] * self[2] + other[4] * self[1]
}
end
function normalize(self)
local len = math.sqrt(self[1] ^ 2 + self[2] ^ 2 + self[3] ^ 2 + (self[4] ^ 4))
local res = {}
for key, value in pairs(self) do
res[key] = value / len
end
return res
end
function conjugate(self)
return {
-self[1],
-self[2],
-self[3],
self[4]
}
end
function inverse(self)
return modlib.vector.divide_scalar(conjugate(self), self[1] ^ 2 + self[2] ^ 2 + self[3] ^ 2 + self[4] ^ 2)
end
function negate(self)
for key, value in pairs(self) do
self[key] = -value
end
end
function dot(self, other)
return self[1] * other[1] + self[2] * other[2] + self[3] * other[3] + self[4] * other[4]
end
--: self normalized quaternion
--: other normalized quaternion
function slerp(self, other, ratio)
local d = dot(self, other)
if d < 0 then
d = -d
negate(other)
end
-- Threshold beyond which linear interpolation is used
if d > 1 - 1e-10 then
return modlib.vector.interpolate(self, other, ratio)
end
local theta_0 = math.acos(d)
local theta = theta_0 * ratio
local sin_theta = math.sin(theta)
local sin_theta_0 = math.sin(theta_0)
local s_1 = sin_theta / sin_theta_0
local s_0 = math.cos(theta) - d * s_1
return modlib.vector.add(modlib.vector.multiply_scalar(self, s_0), modlib.vector.multiply_scalar(other, s_1))
end
--> {x = pitch, y = yaw, z = roll} euler rotation in degrees
function to_euler_rotation(self)
local rotation = {}
local sinr_cosp = 2 * (self[4] * self[1] + self[2] * self[3])
local cosr_cosp = 1 - 2 * (self[1] ^ 2 + self[2] ^ 2)
rotation.x = math.atan2(sinr_cosp, cosr_cosp)
local sinp = 2 * (self[4] * self[2] - self[3] * self[1])
if sinp <= -1 then
rotation.z = -math.pi/2
elseif sinp >= 1 then
rotation.z = math.pi/2
else
rotation.z = math.asin(sinp)
end
local siny_cosp = 2 * (self[4] * self[3] + self[1] * self[2])
local cosy_cosp = 1 - 2 * (self[2] ^ 2 + self[3] ^ 2)
rotation.y = math.atan2(siny_cosp, cosy_cosp)
return vector.apply(rotation, math.deg)
end
-- See https://github.com/zaki/irrlicht/blob/master/include/quaternion.h#L652
function to_euler_rotation_irrlicht(self)
local x, y, z, w = unpack(self)
local test = 2 * (y * w - x * z)
local function _calc()
if math.abs(test - 1) <= 1e-6 then
return {
z = -2 * math.atan2(x, w),
x = 0,
y = math.pi/2
}
end
if math.abs(test + 1) <= 1e-6 then
return {
z = 2 * math.atan2(x, w),
x = 0,
y = math.pi/-2
}
end
return {
z = math.atan2(2 * (x * y + z * w), x ^ 2 - y ^ 2 - z ^ 2 + w ^ 2),
x = math.atan2(2 * (y * z + x * w), -x ^ 2 - y ^ 2 + z ^ 2 + w ^ 2),
y = math.asin(math.min(math.max(test, -1), 1))
}
end
return vector.apply(_calc(), math.deg)
end

View File

@ -349,7 +349,7 @@ function find(list, value)
return index
end
end
return false
return
end
contains = find

View File

@ -94,11 +94,65 @@ end
local colorspec = modlib.minetest.colorspec.from_number(0xDDCCBBAA)
assert(modlib.table.equals(colorspec, {a = 0xAA, b = 0xBB, g = 0xCC, r = 0xDD,}), dump(colorspec))
-- in-game tests
-- k-d-tree
local vectors = {}
for _ = 1, 1000 do
table.insert(vectors, {math.random(), math.random(), math.random()})
end
local kdtree = modlib.kdtree.new(vectors)
for _, vector in ipairs(vectors) do
local neighbor, distance = kdtree:get_nearest_neighbor(vector)
assert(modlib.vector.equals(vector, neighbor), distance == 0)
end
for _ = 1, 1000 do
local vector = {math.random(), math.random(), math.random()}
local _, distance = kdtree:get_nearest_neighbor(vector)
local min_distance = math.huge
for _, other_vector in ipairs(vectors) do
local other_distance = modlib.vector.distance(vector, other_vector)
if other_distance < min_distance then
min_distance = other_distance
end
end
assert(distance == min_distance)
end
-- in-game tests & b3d testing
local tests = {
-- depends on player_api
b3d = false,
liquid_dir = false,
liquid_raycast = false
}
if tests.b3d then
local stream = io.open(modlib.mod.get_resource("player_api", "models", "character.b3d"), "r")
assert(stream)
local b3d = modlib.b3d.read(stream)
--! dirty helper method to create truncate tables with 10+ number keys
local function _b3d_truncate(table)
local count = 1
for key, value in pairs(table) do
if type(key) == "table" then
_b3d_truncate(key)
end
if type(value) == "table" then
_b3d_truncate(value)
end
count = count + 1
if type(key) == "number" and count >= 9 and next(table, key) then
if count == 9 then
table[key] = "TRUNCATED"
else
table[key] = nil
end
end
end
return table
end
modlib.file.write(modlib.mod.get_resource"character.b3d.lua", "return " .. dump(_b3d_truncate(modlib.table.copy(b3d))))
stream:close()
end
if tests.liquid_dir then
minetest.register_abm{
label = "get_liquid_corner_levels & get_liquid_direction test",

View File

@ -42,6 +42,7 @@ function to_xyzw(v)
return {x = v[1], y = v[2], z = v[3], w = v[4]}
end
--+ not necessarily required, as Minetest respects the metatable
function to_minetest(v)
return mt_vector.new(unpack(v))
end
@ -115,10 +116,16 @@ metatable.__sub = subtract
metatable.__mul = multiply
metatable.__div = divide
--+ linear interpolation
--: ratio number from 0 (all the first vector) to 1 (all the second vector)
function interpolate(v, other_v, ratio)
return add(multiply(v, 1 - ratio), multiply(other_v, ratio))
end
function norm(v)
local sum = 0
for _, c in pairs(v) do
sum = sum + c*c
for _, value in pairs(v) do
sum = sum + value ^ 2
end
return sum
end
@ -127,6 +134,15 @@ function length(v)
return math.sqrt(norm(v))
end
-- Minor code duplication for the sake of performance
function distance(v, other_v)
local sum = 0
for key, value in pairs(v) do
sum = sum + (value - other_v[key]) ^ 2
end
return math.sqrt(sum)
end
function normalize(v)
return divide_scalar(v, length(v))
end

View File

@ -13,7 +13,7 @@ assert(loadfile(modpath .. "/api/api_feed_tame.lua"))(S)
assert(loadfile(modpath .. "/api/api_capture.lua"))(S)
assert(loadfile(modpath .. "/api/api_tamagochi.lua"))(S)
assert(loadfile(modpath .. "/api/api_breed.lua"))(S)
assert(loadfile(modpath .. "/api/api_wool_milk.lua"))()
assert(loadfile(modpath .. "/api/api_wool_milk.lua"))(S)
assert(loadfile(modpath .. "/api/api_mount.lua"))()
assert(loadfile(modpath .. "/api/api_dreamcatcher.lua"))(S)
assert(loadfile(modpath .. "/api/api_eggs.lua"))()

View File

@ -2,6 +2,8 @@
---Refill lamb or milk
---
local S = ...
petz.refill = function(self)
if self.type == "lamb" then
petz.lamb_wool_regrow(self)
@ -66,6 +68,10 @@ petz.milk_refill = function(self)
end
petz.milk_milk = function(self, clicker)
if not self.is_male then
minetest.chat_send_player(clicker:get_player_name(), S("Milk only female animals!"))
return
end
local inv = clicker:get_inventory()
local wielded_item = clicker:get_wielded_item()
wielded_item:take_item()

View File

@ -131,6 +131,7 @@ Male=Macho
Merry Christmas=Feliz Natal
Mini Lamb Chop=Costeleta de cordeiro
Milk Bucket=Balde de leite
Milk only female animals!=Só leite de animais fêmeas!
more to create the bobbin.=mais para criar a bobina.
Moth=Traça
Mr Pumpkin=Sr. Abóbora

View File

@ -131,6 +131,7 @@ Male=Männlich
Merry Christmas=Frohe Weihnachten
Mini Lamb Chop=Minilammkotelett
Milk Bucket=Milcheimer
Milk only female animals!=Melken Sie nur weibliche Tiere!
more to create the bobbin.=mehr, um die Spule zu erstellen.
Moth=Motte
Mr Pumpkin=Herr Kürbis

View File

@ -131,6 +131,7 @@ Male=Macho
Merry Christmas=Feliz Navidad
Mini Lamb Chop=Chuletilla de cordero
Milk Bucket=Balde de leche
Milk only female animals!=¡Ordeña solo hembras!
more to create the bobbin.=más para crear la bobina.
Moth=Polilla
Mr Pumpkin=Señor Calabaza

View File

@ -131,6 +131,7 @@ Male=Mâle
Merry Christmas=Joyeux noël
Mini Lamb Chop=Morceau d'agneau
Milk Bucket=Seau de lait
Milk only female animals!=Ne traitez que les femelles!
more to create the bobbin.=plus pour créer la bobine.
Moth=Papillon de nuit
Mr Pumpkin=Mr Citrouille

View File

@ -131,6 +131,7 @@ Male=Самец
Merry Christmas=С Рождеством!
Mini Lamb Chop=Отбивная из ягненка
Milk Bucket=Ведро с молоком
Milk only female animals!=Доите только самки!
more to create the bobbin.=больше для создания катушки.
Moth=Мотылёк.
Mr Pumpkin=Мистер Тыква

View File

@ -1,7 +1,7 @@
function petz.hq_terrestial_jump(self, prty)
--Check igf not water or air (cliff)
local node_name = petz.node_name_in(self, "front_below")
if minetest.registered_nodes[node_name]["liquidtype"] == "source" or
if not(node_name) or minetest.registered_nodes[node_name]["liquidtype"] == "source" or
minetest.registered_nodes[node_name]["liquidtype"] == "flowing" or
node_name == "air" then
return

View File

@ -48,15 +48,20 @@ function petz.semiaquatic_brain(self)
end
end
-- hunt a prey (frogs)
if prty < 12 then -- if not busy with anything important
petz.bh_hunt(self, 12, false)
end
if prty < 10 then
if player then
if not(self.tamed) or (self.tamed and self.status == "guard" and player:get_player_name() ~= self.owner) then
local player_pos = player:get_pos()
if vector.distance(pos, player_pos) <= self.view_range then -- if player close
if vector.distance(pos, player_pos) <= self.view_range then -- if player close
if self.warn_attack then --attack player
mobkit.clear_queue_high(self) -- abandon whatever they've been doing
mobkit.clear_queue_high(self) -- abandon whatever they've been doing
if petz.isinliquid(self) then
mobkit.hq_aqua_attack(self, 10, player, 6) -- get revenge
mobkit.hq_aqua_attack(self, 10, player, 6) -- get revenge
else
petz.hq_hunt(self, 10, player)
end
@ -66,6 +71,17 @@ function petz.semiaquatic_brain(self)
end
end
if prty < 8 then
if (self.can_jump) and not(self.status) then
local random_number = math.random(1, self.jump_ratio)
if random_number == 1 then
--minetest.chat_send_player("singleplayer", "jump")
mobkit.clear_queue_high(self)
petz.hq_terrestial_jump(self, 8)
end
end
end
if prty < 6 then
petz.bh_replace(self)
end

View File

@ -110,6 +110,9 @@ end
function petz.check_ground_suffocation(self)
if self.can_fly then --some fying mobs can escape from cages by the roof
return
end
local spos = mobkit.get_stand_pos(self)
spos.y = spos.y + 0.01
if self.type and mobkit.is_alive(self) and not(self.is_baby) then

View File

@ -271,6 +271,7 @@ panda_copulation_distance = 2
##Frog Specific
frog_follow = fireflies:firefly
frog_preys = petz:ant,petz:queen_ant
frog_spawn_nodes = default:dirt_with_grass,default:river_water_source
frog_spawn_chance = 0.6
frog_spawn_biome = default
@ -514,11 +515,13 @@ snow_leopard_spawn_biome = default
##Ant Specific
ant_preys = petz:queen_ant
ant_predators = petz:frog
##Queen Ant Specific
queen_ant_spawn_chance = 0.4
queen_ant_spawn_nodes = default:dirt_with_grass,default:desert_sand
queen_ant_preys = petz:queen_ant
queen_ant_predators = petz:frog
queen_ant_spawn_biome = default
##Bunny Specific

View File

@ -21,6 +21,9 @@ minetest.register_entity("petz:"..pet_name,{
give_orders = false,
can_be_brushed = false,
capture_item = "net",
can_jump = true,
jump_ratio = 10,
jump_impulse = 4.0,
follow = petz.settings.frog_follow,
drops = {
{name = "petz:frog_leg", chance = 1, min = 1, max = 1,},
@ -48,6 +51,7 @@ minetest.register_entity("petz:"..pet_name,{
animation = {
walk={range={x=26, y=38}, speed=25, loop=true},
run={range={x=26, y=38}, speed=30, loop=true},
jump={range={x=26, y=38}, speed=10, loop=true},
stand={
{range={x=0, y=12}, speed=5, loop=true},
},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
tamagochi_mode = false
shears = mobs:shears

View File

@ -49,6 +49,7 @@ local function croc_brain(self)
end
if mobkit.timer(self,1) then
local prty = mobkit.get_queue_priority(self)
if not mobkit.recall(self,"landlife") and not mobkit.recall(self,"waterlife") then
mobkit.remember(self,"waterlife",os.time())
@ -68,7 +69,7 @@ local function croc_brain(self)
end
end
local prty = mobkit.get_queue_priority(self)
if prty < 20 then
local target = mobkit.get_nearby_player(self)

View File

@ -98,6 +98,18 @@ function water_life_get_biome_data(pos)
return biome
end
-- get list of biome names
function water_life.get_biomes()
local biomes = {}
for k,v in pairs(minetest.registered_biomes) do
table.insert(biomes, k)
end
if #biomes > 0 then return biomes else return nil end
end
-- returns closest enemy or player, if player is true enemies must be in entity definition: predators = {[name1]=1,[name2]=1,.....}

View File

@ -0,0 +1,912 @@
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local sqrt = math.sqrt
local max = math.max
local min = math.min
local pow = math.pow
local sign = math.sign
local time = os.time
local rad = math.rad
local deg=math.deg
local tan = math.tan
local cos = math.cos
local atan=math.atan
local neighbors ={
{x=1,z=0},
{x=1,z=1},
{x=0,z=1},
{x=-1,z=1},
{x=-1,z=0},
{x=-1,z=-1},
{x=0,z=-1},
{x=1,z=-1}
}
-- pseudo random generator, init and call function
water_life.randomtable = PcgRandom(math.random(2^23)+1)
function water_life.random(min,max)
if not min and not max then return math.abs(water_life.randomtable:next() / 2^31) end
if not max then
max = min
min = 1
end
if max and not min then min = 1 end
if max < min then return water_life.randomtable:next(max,min) end
return water_life.randomtable:next(min,max)
end
--
local random = water_life.random -- do not delete, this MUST be here!
--
--checks if entity is in a small water pool
function water_life.check_for_pool(self,deep,minr,pos)
if not self and not pos then return nil end
if not deep then deep = 3 end
if not minr then minr = 3 end
local max = 16
if not pos then
pos = self.object:get_pos()
end
local d,t,s = water_life.water_depth(pos,max)
if not d then return nil end
local cpos = {}
local ispool = 0
for i = 0,270,90 do
cpos = mobkit.pos_translate2d(pos,rad(i),minr)
if water_life.find_collision(pos,cpos,false) then ispool = ispool + 1 end
end
if ispool > 2 and d < deep then return true end
return false
end
-- returns ingame time, 1 = morning, 2 = noon, 3 = afternoon, 4 = night
function water_life.get_game_time()
local time = minetest.get_timeofday()
local hour = math.floor(time*24)
if hour >= 5 and hour < 10 then return 1 end
if hour >= 10 and hour < 15 then return 2 end
if hour >= 15 and hour < 20 then return 3 end
if hour > 20 or hour < 5 then return 4 end
end
function water_life_get_biome_data(pos)
if not pos then return nil end
local table = minetest.get_biome_data(pos)
if not table then return nil end
local biome = {}
biome.id = table.biome
biome.name = minetest.get_biome_name(table.biome)
biome.temp = math.floor((table.heat-32)*5/9) --turn fahrenheit into celsius
biome.humid = math.floor(table.humidity*100)/100
return biome
end
-- get list of biome names
function water_life.get_biomes()
local biomes = {}
for k,v in pairs(minetest.registered_biomes) do
table.insert(biomes, k)
end
if #biomes > 0 then return biomes else return nil end
end
-- returns closest enemy or player, if player is true enemies must be in entity definition: predators = {[name1]=1,[name2]=1,.....}
function water_life.get_closest_enemy(self,player)
local cobj = nil
local dist = water_life.abr*64
local pos = self.object:get_pos()
local otable = minetest.get_objects_inside_radius(pos, self.view_range)
if not self.predators and not player then return nil end
for _,obj in ipairs(otable) do
local luaent = obj:get_luaentity()
if mobkit.is_alive(obj) and not obj:is_player() and luaent and self.predators[luaent.name] then
local opos = obj:get_pos()
local odist = abs(opos.x-pos.x) + abs(opos.z-pos.z)
if odist < dist then
dist=odist
cobj=obj
end
elseif mobkit.is_alive(obj) and obj:is_player() and player then
local opos = obj:get_pos()
local odist = abs(opos.x-pos.x) + abs(opos.z-pos.z)
if odist < dist then
dist=odist
cobj=obj
end
end
end
return cobj
end
--player knockback from entity
function water_life.knockback_player(self,target,force)
if not target:is_player() then return end
if not self.object then return end
if not force then force = 10 end
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir = vector.multiply(dir, force)
dir = {x=dir.x, y=dir.y+force/2, z= dir.z}
target:add_player_velocity(dir)
end
--sets an urchin somewhere but not in the center of a node
function water_life.set_urchin(pos,name)
if not pos then return end
if not name then name = "water_life:urchin" end
local x = random()/2
local z = random()/2
if water_life.leftorright() then pos.x = pos.x +x else pos.x=pos.x - x end
if water_life.leftorright() then pos.z = pos.z +z else pos.z=pos.z - z end
local obj = minetest.add_entity(pos, name)
return obj
end
-- add vector cross function for flying behavior if not yet there
if vector and not vector.cross then
function vector.cross(a, b)
return {
x = a.y * b.z - a.z * b.y,
y = a.z * b.x - a.x * b.z,
z = a.x * b.y - a.y * b.x
}
end
end
-- show temp marker
function water_life.temp_show(pos,time,pillar)
if not pos then return end
if not time then time = 5 end
local step = 1
if not pillar then pillar = 1 end
if pillar < 0 then step = -1 end
for i = 1,pillar,step do
local obj = minetest.add_entity({x=pos.x, y=pos.y+i, z=pos.z}, "water_life:pos")
if obj then
minetest.after(time, function(obj) obj:remove() end, obj)
end
end
end
-- throws a coin
function water_life.leftorright()
local rnd = random()
if rnd > 0.5 then return true else return false end
end
-- distance from self to target
function water_life.dist2tgt(self,tgt)
local pos = mobkit.get_stand_pos(self)
local tpos = tgt:get_pos()
return vector.distance(pos,tpos)
end
function water_life.dumbstep(self,height,tpos,speed_factor,idle_duration)
if height <= 0.001 then
mobkit.lq_turn2pos(self,tpos)
water_life.lq_dumbwalk(self,tpos,speed_factor)
else
mobkit.lq_turn2pos(self,tpos)
water_life.lq_dumbjump(self,height)
end
idle_duration = idle_duration or 6
mobkit.lq_idle(self,random(ceil(idle_duration*0.5),idle_duration))
end
-- drop on death what is definded in the entity table
function water_life.handle_drops(self)
if not self.drops then return end
for _,item in ipairs(self.drops) do
local amount = random (item.min, item.max)
local chance = random(1,100)
local pos = self.object:get_pos()
pos.y = pos.y + self.collisionbox[5] +1
if chance < (100/item.chance) then
local obj = minetest.add_item(pos, item.name.." "..tostring(amount))
end
end
end
function water_life.register_shark_food(name)
table.insert(water_life.shark_food,name)
end
function water_life.register_gull_bait(name)
if name then water_life.gull_bait[name] = 1 end
end
function water_life.feed_shark(self)
for i = 1,#water_life.shark_food,1 do
if water_life.shark_food[i] ~= "water_life:fish" and water_life.shark_food[i] ~= "water_life:fish_tamed" then
local target = mobkit.get_closest_entity(self,water_life.shark_food[i])
if target then
return target
end
end
end
return nil
end
function water_life.get_close_drops(self,name)
local objs = minetest.get_objects_inside_radius(self.object:get_pos(), self.view_range)
if #objs < 1 then return nil end
for i = #objs,1,-1 do
local entity = objs[i]:get_luaentity()
if not entity or not entity.name == "__builtin:item" then table.remove(objs,i) end -- remove any entity different from a drop
end
if #objs < 1 then return nil end
if not name then return objs[random(#objs)] end -- no name, return random drop
for i=#objs,1,-1 do
local entity = objs[i]:get_luaentity()
if not entity.itemstring then
table.remove(objs,i)
else
if not string.match(entity.itemstring,name) then table.remove(objs,i) end -- remove anything different from name
end
end
if #objs < 1 then
return nil
else
return objs[random(#objs)]
end
end
function water_life.inwater(obj)
if not obj then return nil end
local pos = obj:get_pos()
local node = minetest.get_node(pos)
if not node or node.name == 'ignore' then return nil end
if not minetest.registered_nodes[node.name] then return nil end -- handle unknown nodes
local type = minetest.registered_nodes[node.name]["liquidtype"]
if type == "none" then return nil end
return true
end
function water_life.aqua_radar_dumb(pos,yaw,range,reverse,shallow) -- same as mobkit's but added shallow water if true
range = range or 4
local function okpos(p)
local node = mobkit.nodeatpos(p)
if node then
if node.drawtype == 'liquid' then
local nodeu = mobkit.nodeatpos(mobkit.pos_shift(p,{y=1}))
local noded = mobkit.nodeatpos(mobkit.pos_shift(p,{y=-1}))
if ((nodeu and nodeu.drawtype == 'liquid') or (noded and noded.drawtype == 'liquid')) or shallow then
return true
else
return false
end
else
local h,l = mobkit.get_terrain_height(p)
if h then
local node2 = mobkit.nodeatpos({x=p.x,y=h+1.99,z=p.z})
if node2 and node2.drawtype == 'liquid' then return true, h end
else
return false
end
end
else
return false
end
end
local fpos = mobkit.pos_translate2d(pos,yaw,range)
local ok,h = okpos(fpos)
if not ok then
local ffrom, fto, fstep
if reverse then
ffrom, fto, fstep = 3,1,-1
else
ffrom, fto, fstep = 1,3,1
end
for i=ffrom, fto, fstep do
local ok,h = okpos(mobkit.pos_translate2d(pos,yaw+i,range))
if ok then return yaw+i,h end
ok,h = okpos(mobkit.pos_translate2d(pos,yaw-i,range))
if ok then return yaw-i,h end
end
return yaw+pi,h
else
return yaw, h
end
end
-- counts animals in specified radius or active_block_range, returns a table containing numbers
function water_life.count_objects(pos,radius,name)
if not radius then radius = water_life.abr * 16 end
local all_objects = minetest.get_objects_inside_radius(pos, radius)
local hasil = {}
hasil.whales = 0
hasil.sharks = 0
hasil.fish = 0
hasil.name = 0
hasil.all = #all_objects or 0
local _,obj
for _,obj in ipairs(all_objects) do
local entity = obj:get_luaentity()
if name then
if entity and entity.name == name then
hasil.name = hasil.name +1
end
end
if entity and entity.name == "water_life:whale" then
hasil.whales = hasil.whales +1
elseif entity and entity.name == "water_life:shark" then
hasil.sharks = hasil.sharks +1
elseif entity and (entity.name == "water_life:fish" or entity.name == "water_life:fish_tamed") then
hasil.fish = hasil.fish +1
end
if entity and entity.name then
if not hasil[entity.name] then
hasil[entity.name] = 1
else
hasil[entity.name] = hasil[entity.name] +1
end
end
end
return hasil
end
function water_life.get_herd_members(self,radius)
local pos = mobkit.get_stand_pos(self)
local name = self.name
if not radius then radius = water_life.abo * 16 end
local all_objects = minetest.get_objects_inside_radius(pos, radius)
if #all_objects < 1 then return nil end
for i = #all_objects,1,-1 do
local entity = all_objects[i]:get_luaentity()
if entity and entity.name ~= name then
table.remove(all_objects,i)
end
end
if #all_objects < 1 then
return nil
else
return all_objects
end
end
-- returns 2D angle from self to target in radians
function water_life.get_yaw_to_object(self,target)
local pos = mobkit.get_stand_pos(self)
local tpos = target:get_pos()
local tyaw = minetest.dir_to_yaw(vector.direction(pos, tpos))
return tyaw
end
-- returns 2D angle from self to pos in radians
function water_life.get_yaw_to_pos(self,tpos)
local pos = mobkit.get_stand_pos(self)
local tyaw = minetest.dir_to_yaw(vector.direction(pos, tpos))
return tyaw
end
function water_life.isinliquid(target)
if not target then return false end
local nodepos = mobkit.get_stand_pos(target)
local node1 = mobkit.nodeatpos(nodepos)
nodepos.y = nodepos.y -1
local node2 = mobkit.nodeatpos(nodepos)
if node1 and node1.drawtype=='liquid' or (node2 and node2.drawtype=='liquid' and node1 and node1.drawtype=='airlike') then
return true
end
end
-- find if there is a node between pos1 and pos2
-- water = true means water = obstacle
-- returns distance to obstacle in nodes or nil
function water_life.find_collision(pos1,pos2,water,objects)
local ray = minetest.raycast(pos1, pos2, objects, water)
for pointed_thing in ray do
if pointed_thing.type == "node" then
local dist = math.floor(vector.distance(pos1,pointed_thing.under))
return dist
end
end
return nil
end
-- fast radar, less accurate
-- yaw-x to the right, yaw + x to the left !
-- sonar = true water is no obstacle
function water_life.radar_fast(self,dist,sonar)
local water = not sonar
if not dist then dist = self.view_range end
local angel = atan(3/dist)
local yaw = self.object:get_yaw()
local tpos = self.object:get_pos()
local tapos = mobkit.pos_translate2d(tpos,(yaw-angel),dist)
local tbpos = mobkit.pos_translate2d(tpos,yaw,dist)
local tcpos = mobkit.pos_translate2d(tpos,(yaw+angel),dist)
local tupos = mobkit.pos_shift(tbpos,{y=2})
local tdpos = mobkit.pos_shift(tbpos,{y=-2})
local right = water_life.find_collision(tpos,tapos,water)
local left = water_life.find_collision(tpos,tcpos,water)
local center = water_life.find_collision(tpos,tbpos,water)
local up = water_life.find_collision(tpos,tupos,water)
local down = water_life.find_collision(tpos,tdpos,water)
return left,right,center,up,down
end
-- WIP radar, not ready to use !
function water_life.radar_fast_cols(obj,dist,sonar,rev) --sonar = true, water no obstacle :: rev = true array contains possible positions
if not dist then dist = 3 end
local pos = obj:get_pos()
local yaw = 0
local box = {}
local counter = 1
local rarray = {}
if obj:is_player() then
yaw = obj:get_look_horizontal()
box = obj:get_properties().collisionbox
else
yaw = obj:get_yaw()
if obj:get_luaentity().name == "water_life:whale" then yaw = yaw + rad(180) end
box = obj:get_luaentity().collisionbox
end
local vec = minetest.yaw_to_dir(yaw)
local crasha = mobkit.get_box_displace_cols(pos,box,vec,dist)
if crasha then
for i = #crasha,1,-1 do
for j = #crasha[i],1,-1 do
local cpos ={x=crasha[i][j].x, y= pos.y, z= crasha[i][j].z}
--local cyaw = abs(math.floor(minetest.dir_to_yaw(vector.direction(pos,cpos))*10))
local node = minetest.get_node(cpos)
if minetest.registered_nodes[node.name] then
local kill = false
if minetest.registered_nodes[node.name]["drawtype"] == "airlike" then kill = true end
if minetest.registered_nodes[node.name]["buildable_to"] then kill = true end
if minetest.registered_nodes[node.name]["drawtype"] == "liquid" then kill = sonar end
if kill then
if not rev then
table.remove(crasha[i],j)
else
rarray[counter] = cpos
counter = counter +1
end
else
if not rev then
rarray[counter] = cpos
counter = counter +1
else
table.remove(crasha[i],j)
end
end
end
end
end
end
return rarray
end
-- radar function for obstacles lying in front of an entity
-- use water = true if water should be an obstacle
function water_life.radar(pos, yaw, radius, water,fast)
if not radius or radius < 1 then radius = 16 end
local left = 0
local right = 0
if not water then water = false end
for j = 0,3,1 do
for i = 0,4,1 do
local pos2 = mobkit.pos_translate2d(pos,yaw+(i*pi/16),radius)
local pos3 = mobkit.pos_translate2d(pos,yaw-(i*pi/16),radius)
--minetest.set_node(pos2,{name="default:stone"})
if water_life.find_collision(pos,{x=pos2.x, y=pos2.y + j*2, z=pos2.z}, water) then
left = left + 5 - i
end
if water_life.find_collision(pos,{x=pos3.x, y=pos3.y + j*2, z=pos3.z},water) then
right = right + 5 - i
end
end
end
local up =0
local down = 0
if not fast then
for j = -4,4,1 do
for i = -3,3,1 do
local k = i
local pos2 = mobkit.pos_translate2d(pos,yaw+(i*pi/16),radius)
local collide = water_life.find_collision(pos,{x=pos2.x, y=pos2.y + j, z=pos2.z}, water)
if k < 0 then k = k * -1 end
if collide and j <= 0 then
down = down + math.floor((7+j-k)*collide/radius*2)
elseif collide and j >= 0 then
up = up + math.floor((7-j-k)*collide/radius*2)
end
end
end
end
local under = water_life.find_collision(pos,{x=pos.x, y=pos.y - radius, z=pos.z}, water)
if not under then under = radius end
local above = water_life.find_collision(pos,{x=pos.x, y=pos.y + radius, z=pos.z}, water)
if not above then above = radius end
if water_life.radar_debug then
-- minetest.chat_send_all(dump(water_life.radar_debug).." left = "..left.." right = "..right.." up = "..up.." down = "..down.." under = "..under.." above = "..above)
end
return left, right, up, down, under, above
end
--find a spawn position under air
function water_life.find_node_under_air(pos,radius,name)
if not pos then return nil end
if not radius then radius = 3 end
if not name then name={"group:crumbly","group:stone","group:tree"} end
local pos1 = {x=pos.x-radius, y=pos.y-radius, z=pos.z-radius} --mobkit.pos_shift(pos,{x=radius*-1,y=radius*-1,z=radius*-1})
local pos2 = {x=pos.x+radius, y=pos.y+radius, z=pos.z+radius} --mobkit.pos_shift(pos,{x=radius,y=radius,z=radius})
local spawner = minetest.find_nodes_in_area_under_air(pos1, pos2, name)
if not spawner or #spawner < 1 then
return nil
else
local rpos = spawner[random(#spawner)]
rpos = mobkit.pos_shift(rpos,{y=1})
return rpos
end
end
-- function to find liquid surface and depth at that position
function water_life.water_depth(pos,max)
local surface = {}
local depth = 0
local type = ""
if not max then max = 10 end
if not pos then return nil end
local tempos = {}
local node = minetest.get_node(pos)
if not node or node.name == 'ignore' then return nil end
if not minetest.registered_nodes[node.name] then return nil end -- handle unknown nodes
local type = minetest.registered_nodes[node.name]["liquidtype"]
local found = false
--minetest.chat_send_all(">>>"..dump(node.name).." <<<")
if type == "none" then -- start in none liquid try to find surface
local under = water_life.find_collision(pos,{x=pos.x, y=pos.y - max, z=pos.z}, true)
--minetest.chat_send_all(dump(under).." "..dump(node.name))
if under then
local check = {x=pos.x, y=pos.y - under-1, z=pos.z}
local cname = minetest.get_node(check).name
if not minetest.registered_nodes[cname] then return nil end -- handle unknown nodes
if minetest.registered_nodes[cname]["liquidtype"] == "source" then
surface = check
found = true
end
end
if not found then
return nil
end
else -- start in liquid find way up first
local lastpos = pos
for i = 1,max,1 do
tempos = {x=pos.x, y=pos.y+i, z= pos.z}
node = minetest.get_node(tempos)
if not minetest.registered_nodes[node.name] then return nil end -- handle unknown nodes
local ctype = minetest.registered_nodes[node.name]["liquidtype"]
if ctype == "none" then
surface = lastpos
found = true
break
end
lastpos = tempos
end
if not found then surface = lastpos end
end
pos = surface
type = minetest.get_node(pos).name or ""
local under = water_life.find_collision(pos,{x=pos.x, y=pos.y - max, z=pos.z}, false)
depth = under or max
return depth, type, surface
end
-- amphibious version of mobkit
function water_life.get_next_waypoint_fast(self,tpos,nogopos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = mobkit.dir2neighbor(dir)
local height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor)
local heightr = nil
local heightl = nil
local liq = nil
if height then
local fast = false
heightl = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
heightr = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
fast = true
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
return height, pos2, fast
else
for i=1,4 do
-- scan left
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-i))
if height then return height,pos2 end
-- scan right
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,i))
if height then return height,pos2 end
end
end
end
-- amphibious version of mobkit
function water_life.goto_next_waypoint(self,tpos)
local height, pos2 = water_life.get_next_waypoint_fast(self,tpos)
if not height then return false end
if height <= 0.01 then
local yaw = self.object:get_yaw()
local tyaw = minetest.dir_to_yaw(vector.direction(self.object:get_pos(),pos2))
if abs(tyaw-yaw) > 1 then
mobkit.lq_turn2pos(self,pos2)
end
mobkit.lq_dumbwalk(self,pos2)
else
mobkit.lq_turn2pos(self,pos2)
mobkit.lq_dumbjump(self,height)
end
return true
end
function water_life.get_next_waypoint(self,tpos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = mobkit.dir2neighbor(dir)
local function update_pos_history(self,pos)
table.insert(self.pos_history,1,pos)
if #self.pos_history > 2 then table.remove(self.pos_history,#self.pos_history) end
end
local nogopos = self.pos_history[2]
local height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor)
--minetest.chat_send_all('pos2 ' .. minetest.serialize(pos2))
--minetest.chat_send_all('nogopos ' .. minetest.serialize(nogopos))
if height and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
local heightl = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
local heightr = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
update_pos_history(self,pos2)
return height, pos2
else
for i=1,3 do
-- scan left
local height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
-- scan right
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
--scan rear
height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,4))
if height and not liquidflag
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
-- stuck condition here
table.remove(self.pos_history,2)
self.path_dir = self.path_dir*-1 -- subtle change in pathfinding
end
-- blood effects
function water_life.spilltheblood(object,size)
if not water_life.bloody then return end
if not size then size = 1 end
local particlespawner_id = minetest.add_particlespawner({
amount = 50,
time = 1,
minpos = vector.new(-0.3, size/2, -0.3),
maxpos = vector.new( 0.3, size, 0.3),
minvel = {x = -1, y = 0, z = -1},
maxvel = {x = 1, y = 1, z = 1},
minacc = {x = 0, y = 2, z = 0},
maxacc = {x = 0, y = 3, z = 0},
minexptime = 0.5,
maxexptime = 1,
minsize = 1,
maxsize = 2,
texture = "water_life_bloodeffect1.png",
collisiondetection = true,
collision_removal = true,
object_collision = true,
attached = object,
})
end
-- Entity definitions
-- entity for showing positions in debug
minetest.register_entity("water_life:pos", {
initial_properties = {
visual = "cube",
collide_with_objects = false,
visual_size = {x=1.1, y=1.1},
textures = {"water_life_pos.png", "water_life_pos.png",
"water_life_pos.png", "water_life_pos.png",
"water_life_pos.png", "water_life_pos.png"},
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
physical = false,
}
})
if water_life.radar_debug then
minetest.register_on_player_hpchange(function(player, hp_change, reason)
if not player or hp_change >= 0 then return hp_change end
local name = player:get_player_name()
local privs = minetest.get_player_privs(name)
if not privs.god then return hp_change end
return 0
end, true)
minetest.register_privilege("god", {description ="unvulnerable"})
end
--check here for antiserum group of eaten food
minetest.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing)
if not user or not user:is_player() then return end
if not itemstack then return end
local name = user:get_player_name()
local antiserum = itemstack:get_definition().groups.antiserum
if antiserum then
local meta = user:get_meta()
local score = user:get_hp()
if meta:get_int("snakepoison") > 0 then meta:set_int("snakepoison",0) end
water_life.change_hud(user,"poison",0)
end
return
end)
--new players are immune to snakepoison
minetest.register_on_newplayer(function(player)
if not player or not player:is_player() then return end
local meta = player:get_meta()
local join = os.time()
meta:set_int("jointime",join)
end)
-- but not forever
minetest.register_on_joinplayer(function(player)
if not player or not player:is_player() then return end
local meta = player:get_meta()
meta:set_int("bitten",0)
meta:set_int("repellant",0)
end)

View File

@ -1062,6 +1062,8 @@ function water_life.hq_fly2obj(self,prty,tgt,break_dist,force)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
local tgtpos = tgt:get_pos()
if not tgtpos then return true end
local tgtyaw = tgt:get_yaw() --water_life.get_yaw_to_object(self,tgt)
local tgtspeed = math.floor(vector.length(tgt:get_velocity() or {x=0,y=0,z=0}))
if not tgt:is_player() and tgt:get_luaentity() and tgt:get_luaentity().name == "water_life:whale" then tgtyaw = tgtyaw + rad(180) end -- whales moving backwards XD
@ -1072,6 +1074,7 @@ function water_life.hq_fly2obj(self,prty,tgt,break_dist,force)
wname = stack:get_name()
end
if tgtpos.y < 0 then tgtpos.y = 1 end

View File

@ -73,6 +73,26 @@ minetest.register_chatcommand("wl_kill", {
end
})
minetest.register_chatcommand("wl_lb", {
params = "",
description = "list biomes",
privs = {interact = true},
func = function()
local biom = water_life.get_biomes()
if not biom then return end
for i=1,#biom,1 do
minetest.chat_send_all(dump(i)..") "..dump(biom[i]))
end
end
})
minetest.register_chatcommand("wl_test", {
params = "<mob_name>",
description = "test",

View File

@ -0,0 +1,19 @@
-- check for islands mod
if minetest.get_modpath("islands") then
local bnames = water_life.get_biomes()
water_life.spawn_on_islands = true
if bnames then
for i=1,#bnames,1 do
local keep = string.match(bnames[i],"savanna") or string.match(bnames[i],"rainforest")
if not keep then minetest.unregister_biome(bnames[i]) end
end
end
end

View File

@ -6,7 +6,7 @@
-----------------------------------------------------------
water_life = {}
water_life.version = "020201"
water_life.version = "210207"
water_life.shark_food = {}
water_life.repellant = {}
water_life.gull_bait = {}
@ -43,7 +43,9 @@ water_life.bloody = minetest.settings:get_bool("water_life_bloody") or true
local path = minetest.get_modpath(minetest.get_current_modname())
dofile(path.."/api.lua") -- load water_life api
dofile(path.."/compat.lua")
dofile(path.."/paths.lua") -- load pathfinding
if water_life.muddy_water then dofile(path.."/mapgen.lua") end -- load muddy_water
dofile(path.."/crafts.lua") -- load crafts

View File

@ -0,0 +1,191 @@
-----------------------------------------------------------
--
-- Water_life copyright 2020 by Gundul
-- see software and media licenses in the doc folder
--
-----------------------------------------------------------
water_life = {}
water_life.version = "210207"
water_life.shark_food = {}
water_life.repellant = {}
water_life.gull_bait = {}
water_life.catchNet = "water_life:placeholder"
water_life.petz = minetest.get_modpath("petz")
water_life.mobsredo = minetest.get_modpath("mobs")
water_life.farming = minetest.get_modpath("farming")
water_life.swampz = minetest.get_modpath("swaz")
water_life.abr = tonumber(minetest.settings:get('active_block_range')) or 2
water_life.abo = tonumber(minetest.settings:get('active_object_send_range_blocks')) or 3
water_life.avg_dtime = 0
water_life.max_dtime = 0
-- settingtypes
water_life.whale_spawn_rate = tonumber(minetest.settings:get("water_life_whale_spawn_rate")) or 100
water_life.shark_spawn_rate = tonumber(minetest.settings:get("water_life_shark_spawn_rate")) or 100
water_life.urchin_spawn_rate = tonumber(minetest.settings:get("water_life_urchin_spawn_rate")) or 700
water_life.clams_spawn_rate = tonumber(minetest.settings:get("water_life_clams_spawn_rate")) or 500
water_life.fish_spawn_rate = tonumber(minetest.settings:get("water_life_fish_spawn_rate")) or 1000
water_life.maxwhales = tonumber(minetest.settings:get("water_life_maxwhales")) or 1
water_life.maxsharks = tonumber(minetest.settings:get("water_life_maxsharks")) or 5
water_life.maxmobs = tonumber(minetest.settings:get("water_life_maxmobs")) or 60
water_life.apionly = minetest.settings:get_bool("water_life_apionly") or false
water_life.dangerous = minetest.settings:get_bool("water_life_dangerous") or false
water_life.soundadjust = tonumber(minetest.settings:get("water_life_soundadjust")) or 1.0
water_life.moskitolifetime = tonumber(minetest.settings:get("water_life_moskitolifetime")) or 120 -- lifetime in sec. ( <15 = no reproducing)
water_life.radar_debug = minetest.settings:get_bool("water_life_radar_debug") or false
water_life.muddy_water = minetest.settings:get_bool("water_life_muddy_water") or false
water_life.repeltime = math.floor (720 / (tonumber(minetest.settings:get("time_speed")) or 72)*60) -- the repellent lasts half a minetest day
water_life.newplayerbonus = tonumber(minetest.settings:get("water_life_newplayerbonus")) or 5 -- 5 days savety from rattlenakes for new players
water_life.ihateinsects = minetest.settings:get_bool("water_life_hate_insects") or false
water_life.bloody = minetest.settings:get_bool("water_life_bloody") or true -- let there be blood !
local path = minetest.get_modpath(minetest.get_current_modname())
dofile(path.."/api.lua") -- load water_life api
dofile(path.."/compat.lua")
dofile(path.."/paths.lua") -- load pathfinding
if water_life.muddy_water then dofile(path.."/mapgen.lua") end -- load muddy_water
dofile(path.."/crafts.lua") -- load crafts
dofile(path.."/tools/buoy.lua") -- load buoy
dofile(path.."/chatcommands.lua") -- load chatcommands
dofile(path.."/behaviors.lua") -- load behaviors
dofile(path.."/bio.lua") -- load bio data handles
if not water_life.apionly then
dofile(path.."/hud.lua") -- load player hud
dofile(path.."/spawn.lua") -- load spawn function
dofile(path.."/animals/whale.lua") -- load whales
dofile(path.."/animals/riverfish.lua") -- load riverfish
dofile(path.."/animals/sea_urchin.lua") -- load sea urchin
dofile(path.."/animals/clams.lua") -- load clams
dofile(path.."/flora/plants.lua") -- load water plants
dofile(path.."/flora/corals.lua") -- load corals
dofile(path.."/animals/jellyfish.lua") -- load jellyfish
dofile(path.."/animals/coralfish.lua") -- load coralfish
dofile(path.."/animals/clownfish.lua") -- load clownfish
dofile(path.."/animals/gulls.lua") -- load gulls
dofile(path.."/animals/gecko.lua") -- load tokays
dofile(path.."/animals/beaver.lua") -- load beavers
if not water_life.dangerous then
dofile(path.."/animals/snake.lua") -- load snakes
dofile(path.."/animals/piranha.lua") -- load piranha
dofile(path.."/animals/shark.lua") -- load sharks
dofile(path.."/animals/crocodile.lua") -- load crocodile
dofile(path.."/animals/moskito.lua") -- load moskitos
if water_life.swampz then
dofile(path.."/animals/alligator.lua") -- alligators need swampz mod
end
end
end
--check which lasso to use
if water_life.mobsredo then
water_life.catchBA = "mobs:lasso"
water_life.catchNet = "mobs:net"
if water_life.petz then minetest.unregister_item("petz:lasso") end
elseif water_life.petz then
water_life.catchBA = "petz:lasso"
else
water_life.catchBA = "water_life:lasso"
end
math.randomseed(os.time()) --init random seed
--remove old sharks
minetest.register_entity(":sharks:shark", {
on_activate = function(self, staticdata)
self.object:remove()
end,
})
minetest.register_entity(":zombiestrd:shark", {
on_activate = function(self, staticdata)
self.object:remove()
end,
})
-- register shark food
if minetest.get_modpath("wildlife") then
water_life.register_shark_food("wildlife:deer")
water_life.register_shark_food("wildlife:deer_tamed")
water_life.register_shark_food("wildlife:wolf")
end
if minetest.get_modpath("aerotest") then
water_life.register_shark_food("aerotest:eagle")
end
if minetest.get_modpath("petz") then
water_life.register_shark_food("petz:kitty")
water_life.register_shark_food("petz:rat")
water_life.register_shark_food("petz:goat")
water_life.register_shark_food("petz:puppy")
water_life.register_shark_food("petz:ducky")
water_life.register_shark_food("petz:lamb")
water_life.register_shark_food("petz:camel")
water_life.register_shark_food("petz:calf")
water_life.register_shark_food("petz:chicken")
water_life.register_shark_food("petz:piggy")
water_life.register_shark_food("petz:hamster")
water_life.register_shark_food("petz:chimp")
water_life.register_shark_food("petz:beaver")
water_life.register_shark_food("petz:turtle")
water_life.register_shark_food("petz:penguin")
water_life.register_shark_food("petz:lion")
water_life.register_shark_food("petz:grizzly")
water_life.register_shark_food("petz:pony")
water_life.register_shark_food("petz:wolf")
water_life.register_shark_food("petz:elephant")
water_life.register_shark_food("petz:elephant_female")
water_life.register_shark_food("petz:foxy")
water_life.register_shark_food("petz:polar_bear")
water_life.register_shark_food("petz:tarantula")
water_life.register_shark_food("petz:leopard")
water_life.register_shark_food("petz:snow_leopard")
water_life.register_shark_food("petz:panda")
water_life.register_shark_food("petz:santa_killer")
water_life.register_shark_food("petz:mr_pumpkin")
water_life.register_shark_food("petz:hen")
water_life.register_shark_food("petz:rooster")
end
if minetest.get_modpath("better_fauna") then
water_life.register_shark_food("better_fauna:chicken")
water_life.register_shark_food("better_fauna:cow")
water_life.register_shark_food("better_fauna:pig")
water_life.register_shark_food("better_fauna:sheep")
water_life.register_shark_food("better_fauna:turkey")
end
-- register gull bait
water_life.register_gull_bait("water_life:clownfish")
water_life.register_gull_bait("water_life:coralfish")
water_life.register_gull_bait("water_life:riverfish")
water_life.register_gull_bait("water_life:piranha")
water_life.register_gull_bait("water_life:urchin_item")
water_life.register_gull_bait("water_life:snake_item")
water_life.register_gull_bait("water_life:meat_raw")
water_life.register_gull_bait("water_life:meat")
if minetest.get_modpath("farming") then
water_life.register_gull_bait("farming:bread")
end

View File

@ -8,7 +8,7 @@ local dttimer = 10
local pi = math.pi
local random = water_life.random
local landinterval = 120 -- check every 60 seconds for spawnpos on land
local waterinterval = 40 -- check every 20 seconds for spawnpos in water
local waterinterval = 30 -- check every 20 seconds for spawnpos in water
local function getcount(name)
@ -191,7 +191,7 @@ local function spawnstep(dtime)
local liquidflag = nil
if stype == "default:water_source" then
if stype == "default:water_source" or stype == "islands:water_source" then
liquidflag = "sea"
elseif stype == "default:river_water_source" then
@ -380,11 +380,13 @@ local function spawnstep(dtime)
--minetest.chat_send_all(dump(minetest.pos_to_string(surface)).." "..dump(minetest.pos_to_string(ground)))
mobname = 'water_life:fish'
--local nearlife = water_life.count_objects(pos2,24,"water_life:piranha")
if water_life.fish_spawn_rate >= random(1000) and ((animal.all < (water_life.maxmobs-5)) or getcount(animal[mobname]) < 5) and (liquidflag == "river" or liquidflag == "muddy") then
if water_life.fish_spawn_rate >= random(1000) and ((animal.all < (water_life.maxmobs-5)) or getcount(animal[mobname]) < 5) and (((liquidflag == "river" or liquidflag == "muddy")) or (water_life.spawn_on_islands and not water_life.check_for_pool(nil,2,3,pos2) and
water_life.check_for_pool(nil,2,16,pos2))) then
local table = minetest.get_biome_data(pos)
if not water_life.dangerous and table and water_life.piranha_biomes[minetest.get_biome_name(table.biome)] then
if not water_life.dangerous and ((table and water_life.piranha_biomes[minetest.get_biome_name(table.biome)])
or water_life.spawn_on_islands) then
mobname = "water_life:piranha"
end

View File

@ -27,4 +27,5 @@ Modified Code by Liil/Wilhelmine/Liil (c) 2021
Textures, Models and Animation by Liil/Wilhelmine/Liil under (MIT) License (c) 2021
Sounds are from freesound.org under Creative Commons License. Thanks to Lauramel, Gleith, Theveomammoth11, Vataa, D-Jones, Pol, Robinhood76,
sesmo42 and Missburusdeer2011 for the sounds!
sesmo42, Missburusdeer2011, Hazure, Inspectorj, Benboncan, Spookymodem, Drobiumdesign, J-zazvurek, Benboncan, Felix-blume, Sihil, Kabit, Roubignolle, Egomassive, Florianreichelt and Pillonoise for the sounds!
Thanks to Nagaty Studio for the Hyena Sounds! Source: https://www.youtube.com/c/NagatyStudio/about

View File

@ -0,0 +1,92 @@
mobs:register_mob("animalworld:anteater", {
stepheight = 1,
type = "animal",
passive = false,
attack_type = "dogfight",
group_attack = true,
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 10,
hp_min = 25,
hp_max = 65,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Anteater.b3d",
textures = {
{"textureanteater.png"},
},
makes_footstep_sound = true,
sounds = {
},
walk_velocity = 0.7,
run_velocity = 2,
runaway = false,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine"},
jump = false,
jump_height = 3,
pushable = true,
follow = {"fishing:bait:worm", "bees:frame_full", "ethereal:worm"},
view_range = 10,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
{name = "mobs:leather", chance = 1, min = 0, max = 2},
},
water_damage = 0,
lava_damage = 5,
light_damage = 0,
fear_height = 2,
animation = {
speed_normal = 75,
stand_start = 0,
stand_end = 100,
walk_start = 100,
walk_end = 200,
punch_start = 250,
punch_end = 350,
die_start = 1, -- we dont have a specific death animation so we will
die_end = 2, -- re-use 2 standing frames at a speed of 1 fps and
die_speed = 1, -- have mob rotate when dying.
die_loop = false,
die_rotate = true,
},
on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 50, false, nil) then return end
end,
})
local spawn_on = {"default:dirt_with_rainforest_litter"}
if minetest.get_mapgen_setting("mg_name") ~= "v6" then
spawn_on = {"default:dirt_with_rainforest_litter", "default:dry_dirt_with_dry_grass"}
end
if minetest.get_modpath("ethereal") then
spawn_on = {"ethereal:grass_grove", "ethereal:green_dirt"}
end
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:anteater",
nodes = {"default:dirt_with_rainforest_litter"},
min_light = 0,
interval = 1,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 1,
max_height = 50,
day_toggle = true,
})
end
mobs:register_egg("animalworld:anteater", ("Anteater"), "aanteater.png")
mobs:alias_mob("animalworld:manteater", "animalworld:anteater") -- compatibility

View File

@ -0,0 +1,82 @@
mobs:register_mob("animalworld:bat", {
stepheight = 3,
type = "animal",
passive = true,
attack_type = "dogfight",
attack_animals = false,
reach = 2,
damage = 2,
hp_min = 5,
hp_max = 35,
armor = 100,
collisionbox = {-0.3, -0.01, -1, 0.3, 0.3, 0.3},
visual = "mesh",
mesh = "Bat.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"texturebat.png"},
},
sounds = {
random = "animalworld_bat",
},
makes_footstep_sound = false,
walk_velocity = 5,
run_velocity = 6,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
fall_speed = 0,
jump = true,
jump_height = 6,
fly = true,
stepheight = 3,
drops = {
{name = "mobs:leather", chance = 1, min = 0, max = 2},
},
water_damage = 1,
lava_damage = 4,
light_damage = 0,
fear_height = 0,
animation = {
speed_normal = 130,
stand_start = 0,
stand_end = 100,
walk_start = 150,
walk_end = 250,
fly_start = 150, -- swim animation
fly_end = 250,
-- 50-70 is slide/water idle
},
fly_in = {"air"},
floats = 0,
follow = {
"animalworld:rawfish", "ethereal:worm", "ethereal:fish_raw", "fishing:fish_raw", "xocean:fish_edible"
},
view_range = 4,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:bat",
nodes = {"default:dirt_with_grass"}, {"default:dry_dirt_with_dry_grass"}, {"default:dirt_with_rainforest_litter"}, {"default:dirt_with_coniferous_litter"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 5,
min_height = -100,
max_height = 50,
day_toggle = false,
})
end
mobs:register_egg("animalworld:bat", ("Bat"), "abat.png")

View File

@ -5,10 +5,10 @@ stepheight = 1,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 3,
damage = 8,
hp_min = 15,
hp_max = 40,
armor = 200,
hp_max = 60,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Bear.b3d",
@ -46,7 +46,7 @@ stepheight = 1,
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible"
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible", "farming:melon_slice", "farming:melon_slice", "water_life:meat_raw", "water_life:meat_raw", "fishing:fish_raw", "animalworld:chicken_raw"
},
view_range = 8,

View File

@ -5,10 +5,10 @@ stepheight = 3,
attack_type = "dogfight",
attack_animals = false,
reach = 2,
damage = 1,
damage = 2,
hp_min = 5,
hp_max = 10,
armor = 200,
hp_max = 30,
armor = 100,
collisionbox = {-0.3, -0.01, -1, 0.3, 0.3, 0.3},
visual = "mesh",
mesh = "Blackbird.b3d",
@ -23,7 +23,7 @@ stepheight = 3,
walk_velocity = 2,
run_velocity = 4,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = true,
jump_height = 6,
stepheight = 3,
@ -52,7 +52,7 @@ stepheight = 3,
fly_in = {"air"},
floats = 0,
follow = {
"fishing:bait:worm"
"fishing:bait:worm", "farming:seed_wheat", "farming:seed_rice", "farming:seed_oat", "ethereal:pine_nuts", "ethereal:worm"
},
view_range = 4,
@ -73,6 +73,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 100,
day_toggle = true,

View File

@ -7,10 +7,10 @@ mobs:register_mob("animalworld:boar", {
owner_loyal = true,
attack_npcs = true,
reach = 2,
damage = 2,
damage = 6,
hp_min = 5,
hp_max = 35,
armor = 200,
hp_max = 55,
armor = 100,
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.95, 0.5},
visual = "mesh",
mesh = "Boar.b3d",
@ -27,8 +27,11 @@ mobs:register_mob("animalworld:boar", {
jump = true,
jump_height = 6,
pushable = true,
follow = {"default:apple", "farming:potato"},
follow = {"default:apple", "farming:potato", "ethereal:banana_bread", "farming:melon_slice", "farming:carrot", "farming:seed_rice", "farming:corn"},
view_range = 6,
replace_rate = 10,
replace_what = {"farming:soil", "farming:soil_wet"},
replace_with = "default:dirt",
drops = {
{name = "animalworld:pork_raw", chance = 1, min = 1, max = 3},
},
@ -66,7 +69,7 @@ if minetest.get_mapgen_setting("mg_name") ~= "v6" then
end
if minetest.get_modpath("ethereal") then
spawn_on = {"ethereal:mushroom_dirt", "ethereal:bamboo_dirt"}
spawn_on = {"ethereal:mushroom_dirt", "ethereal:bamboo_dirt", "ethereal:green_dirt", "ethereal:mushroom"}
end
if not mobs.custom_spawn_animal then
@ -76,6 +79,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 1,
max_height = 80,
day_toggle = true,

View File

@ -7,10 +7,10 @@ mobs:register_mob("animalworld:camel", {
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 2,
damage = 5,
hp_min = 20,
hp_max = 40,
armor = 200,
hp_max = 60,
armor = 100,
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.95, 0.7},
visual = "mesh",
mesh = "Camel.b3d",
@ -25,11 +25,11 @@ mobs:register_mob("animalworld:camel", {
walk_velocity = 2,
run_velocity = 5,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine"},
jump = false,
jump_height = 3,
pushable = true,
follow = {"default:dry_shrub ", "default:grass_1"},
follow = {"default:dry_shrub ", "default:grass_1", "ethereal:dry_shrub", "farming:seed_wheat", "farming:seed_rye", "default:junglegrass"},
view_range = 7,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
@ -68,7 +68,7 @@ if minetest.get_mapgen_setting("mg_name") ~= "v6" then
end
if minetest.get_modpath("ethereal") then
spawn_on = {"default:desert_sand"}
spawn_on = {"default:desert_sand", "ethereal:dry_dirt"}
end
if not mobs.custom_spawn_animal then
@ -78,6 +78,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 0,
max_height = 40,
})

View File

@ -7,8 +7,8 @@ stepheight = 0.0,
reach = 1,
damage = 1,
hp_min = 5,
hp_max = 5,
armor = 200,
hp_max = 25,
armor = 100,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 0.95, 0.4},
visual = "mesh",
mesh = "Carp.b3d",
@ -24,7 +24,7 @@ stepheight = 0.0,
fly_in = "default:water_source", "default:river_water_source", "default:water_flowing",
fall_speed = 0,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:elephant", "animalworld:hippo", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:elephant", "animalworld:hippo", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = false,
stepheight = 0.0,
drops = {
@ -50,7 +50,7 @@ stepheight = 0.0,
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
follow = {
"default:kelp", "seaweed", "xocean:kelp",
"ethereal:worm", "seaweed", "fishing:bait_worm",
"default:grass", "farming:cucumber", "farming:cabbage"
},
view_range = 10,
@ -71,6 +71,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 0,
max_height = 30,
day_toggle = true,

View File

@ -7,8 +7,8 @@ stepheight = 1,
reach = 2,
damage = 0,
hp_min = 10,
hp_max = 20,
armor = 200,
hp_max = 40,
armor = 100,
collisionbox = {-0.268, -0.01, -0.268, 0.268, 0.167, 0.268},
visual = "mesh",
mesh = "Crab.b3d",
@ -25,7 +25,7 @@ stepheight = 1,
walk_velocity = 0.7,
run_velocity = 1,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:elephant", "animalworld:hippo", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:elephant", "animalworld:hippo", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = false,
jump_height = 6,
drops = {
@ -49,7 +49,7 @@ stepheight = 1,
follow = {"animalworld:rawfish", "default:marram_grass_2"},
view_range = 5,
replace_rate = 10,
replace_what = {"default:marram_grass_2"},
replace_what = {"default:marram_grass_2", "ethereal:fish_raw", "fishing:fish_raw", "xocean:fish_edible", "water_life:meat_raw", "mobs:clownfish_raw"},
replace_with = "air",
on_rightclick = function(self, clicker)
@ -63,7 +63,7 @@ stepheight = 1,
local spawn_on = "default:sand"
if minetest.get_modpath("ethereal") then
spawn_on = "ethereal:prairie_dirt"
spawn_on = "default:sand"
end
if not mobs.custom_spawn_animal then
@ -73,6 +73,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 2,
})

View File

@ -5,10 +5,10 @@ stepheight = 1,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 6,
damage = 12,
hp_min = 50,
hp_max = 75,
armor = 200,
hp_max = 95,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Crocodile.b3d",
@ -50,7 +50,7 @@ stepheight = 1,
floats = 0,
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible"
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible", "fishing:fish_raw", "water_life:meat_raw", "fishing:carp_raw", "animalworld:chicken_raw"
},
view_range = 12,
@ -70,6 +70,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 0,
max_height = 3,
day_toggle = true,

View File

@ -5,10 +5,10 @@ stepheight = 2,
attack_type = "dogfight",
attack_animals = true,
reach = 3,
damage = 8,
damage = 16,
hp_min = 75,
hp_max = 100,
armor = 200,
hp_max = 120,
armor = 100,
collisionbox = {-2, -0.01, -2, 2, 2, 2},
visual = "mesh",
mesh = "Elephant.b3d",
@ -34,6 +34,7 @@ stepheight = 2,
lava_damage = 4,
light_damage = 0,
fear_height = 4,
pathfinding = true,
animation = {
speed_normal = 80,
stand_start = 0,
@ -47,10 +48,12 @@ stepheight = 2,
follow = {
"ethereal:banana_single", "farming:corn_cob", "farming:cabbage",
"default:apple"
"default:apple", "farming:cabbage", "farming:carrot", "farming:cucumber", "farming:grapes", "farming:pineapple", "ethereal:orange", "ethereal:coconut", "ethereal:coconut_slice"
},
view_range = 6,
replace_rate = 10,
replace_what = {"farming:soil", "farming:soil_wet"},
replace_with = "default:dirt",
on_rightclick = function(self, clicker)
-- feed or tame
@ -67,6 +70,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 65,
day_toggle = true,

View File

@ -0,0 +1,82 @@
mobs:register_mob("animalworld:frog", {
stepheight = 3,
type = "animal",
passive = true,
reach = 1,
attack_npcs = false,
damage = 1,
hp_min = 5,
hp_max = 25,
armor = 100,
collisionbox = {-0.268, -0.01, -0.268, 0.268, 0.167, 0.268},
visual = "mesh",
mesh = "Frog.b3d",
drawtype = "front",
textures = {
{"texturefrog.png"},
},
sounds = {
random = "animalworld_frog",},
makes_footstep_sound = true,
walk_velocity = 2,
run_velocity = 3,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = true,
jump_height = 6,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 6,
animation = {
speed_normal = 100,
stand_start = 1,
stand_end = 100,
walk_start = 100,
walk_end = 200,
fly_start = 250, -- swim animation
fly_end = 350,
},
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
follow = {"fishing:bait:worm", "ethereal:worm"},
view_range = 6,
on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 50, false, nil) then return end
end,
})
local spawn_on = "default:sand"
if minetest.get_modpath("ethereal") then
spawn_on = "ethereal:prairie_dirt", "default:dirt_with_grass", "ethereal:green_dirt"
end
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:frog",
nodes = {"default:dirt_with_grass"}, {"default:dirt_with_rainforest_litter"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = -10,
max_height = 2,
})
end
mobs:register_egg("animalworld:frog", ("Frog"), "afrog.png", 0)
mobs:alias_mob("animalworld:frog", "animalworld:frog") -- compatibility

View File

@ -0,0 +1,92 @@
mobs:register_mob("animalworld:gnu", {
stepheight = 2,
type = "animal",
passive = true,
attack_type = "dogfight",
group_attack = true,
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 2,
hp_min = 30,
hp_max = 60,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Gnu.b3d",
textures = {
{"texturegnu.png"},
},
makes_footstep_sound = true,
sounds = {
random = "animalworld_gnu",
},
walk_velocity = 1,
run_velocity = 5,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = false,
jump_height = 3,
pushable = true,
follow = {"default:apple", "default:dry_dirt_with_dry_grass", "farming:seed_wheat", "default:junglegrass", "farming:seed_oat"},
view_range = 10,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 5,
light_damage = 0,
fear_height = 3,
animation = {
speed_normal = 60,
stand_start = 0,
stand_end = 100,
walk_start = 100,
walk_end = 200,
run_start = 200,
run_end = 300,
die_start = 1, -- we dont have a specific death animation so we will
die_end = 2, -- re-use 2 standing frames at a speed of 1 fps and
die_speed = 1, -- have mob rotate when dying.
die_loop = false,
die_rotate = true,
},
on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 50, false, nil) then return end
end,
})
local spawn_on = {"default:dry_dirt_with_dry_grass"}
if minetest.get_mapgen_setting("mg_name") ~= "v6" then
spawn_on = {"default:dry_dirt_with_dry_grass"}
end
if minetest.get_modpath("ethereal") then
spawn_on = {"default:dry_dirt_with_dry_grass"}
end
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:gnu",
nodes = {"default:dry_dirt_with_dry_grass"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 20,
max_height = 50,
day_toggle = true,
})
end
mobs:register_egg("animalworld:gnu", ("Gnu"), "agnu.png")
mobs:alias_mob("animalworld:gnu", "animalworld:gnu") -- compatibility

View File

@ -4,8 +4,8 @@ stepheight = 1,
passive = true,
reach = 1,
hp_min = 15,
hp_max = 20,
armor = 200,
hp_max = 40,
armor = 100,
collisionbox = {-0.268, -0.01, -0.268, 0.268, 0.167, 0.268},
visual = "mesh",
mesh = "Hare.b3d",
@ -20,7 +20,7 @@ stepheight = 1,
walk_velocity = 3,
run_velocity = 6,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = true,
jump_height = 6,
drops = {
@ -40,10 +40,10 @@ stepheight = 1,
punch_start = 100,
punch_end = 200,
},
follow = {"farming:carrot", "farming_plus:carrot_item", "default:grass_1"},
follow = {"farming:carrot", "farming_plus:carrot_item", "default:grass_1", "farming:carrot_7", "farming:carrot_8", "farming_plus:carrot", "farming:lettuce", "farming:cabbage", "ethereal:snowygrass"},
view_range = 8,
replace_rate = 10,
replace_what = {"farming:carrot_7", "farming:carrot_8", "farming_plus:carrot"},
replace_what = {"farming:carrot_7", "farming:carrot_8", "farming_plus:carrot", "farming:lettuce", "farming:cabbage", "ethereal:snowygrass", "flowers:geranium", "flowers:rose"},
replace_with = "air",
on_rightclick = function(self, clicker)
@ -104,7 +104,7 @@ stepheight = 1,
local spawn_on = "default:dirt_with_grass"
if minetest.get_modpath("ethereal") then
spawn_on = "ethereal:prairie_dirt"
spawn_on = "ethereal:prairie_dirt", "default:dirt_with_grass"
end
if not mobs.custom_spawn_animal then
@ -114,6 +114,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 5,
max_height = 100,
day_toggle = true,

View File

@ -5,10 +5,10 @@ stepheight = 1,
attack_type = "dogfight",
attack_animals = true,
reach = 3,
damage = 6,
damage = 12,
hp_min = 65,
hp_max = 80,
armor = 200,
hp_max = 100,
armor = 100,
collisionbox = {-1.4, -0.01, -1.4, 1.4, 1.4, 1.4},
visual = "mesh",
mesh = "Hippo2.b3d",
@ -51,7 +51,7 @@ fly_in = {"default:water_source", "default:river_water_source", "default:water_f
floats = 0,
follow = {
"ethereal:banana_single", "farming:corn_cob", "farming:cabbage",
"default:apple"
"default:apple", "water_life:meat_raw", "xocean:fish_edible", "ethereal:fish_raw", "ethereal:banana", "farming:cabbage", "farming:lettuce", "farming:melon_slice"
},
view_range = 6,
@ -72,6 +72,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 5,
day_toggle = true,

View File

@ -0,0 +1,77 @@
mobs:register_mob("animalworld:hyena", {
stepheight = 2,
type = "monster",
passive = false,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 16,
hp_min = 35,
hp_max = 65,
armor = 100,
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.95, 0.5},
visual = "mesh",
mesh = "Hyena.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"texturehyena.png"},
},
sounds = {
random = "animalworld_hyena",
attack = "animalworld_hyena",
},
makes_footstep_sound = true,
walk_velocity = 1,
run_velocity = 3,
runaway = false,
jump = true,
jump_height = 6,
stepheight = 2,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 4,
animation = {
speed_normal = 75,
stand_start = 0,
stand_end = 100,
walk_start = 150,
walk_end = 250,
punch_start = 250,
punch_end = 350,
-- 50-70 is slide/water idle
},
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "animalworld:pork_raw", "water_life:meat_raw", "xocean:fish_edible", "animalworld:chicken_raw"
},
view_range = 10,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:hyena",
nodes = {"default:dry_dirt_with_dry_grass"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 30,
max_height = 60,
})
end
mobs:register_egg("animalworld:hyena", ("Hyena"), "ahyena.png")

View File

@ -42,6 +42,22 @@ dofile(path .. "spider.lua") --
dofile(path .. "spidermale.lua") --
dofile(path .. "crab.lua") --
dofile(path .. "reindeer.lua") --
dofile(path .. "volverine.lua") --
dofile(path .. "owl.lua") --
dofile(path .. "frog.lua") --
dofile(path .. "monitor.lua") --
dofile(path .. "gnu.lua") --
dofile(path .. "puffin.lua") --
dofile(path .. "anteater.lua") --
dofile(path .. "hyena.lua") --
dofile(path .. "rat.lua") --
dofile(path .. "vulture.lua") --
dofile(path .. "toucan.lua") --
dofile(path .. "snowleopard.lua") --
dofile(path .. "lobster.lua") --
dofile(path .. "squid.lua") --
dofile(path .. "kobra.lua") --
dofile(path .. "bat.lua") --

View File

@ -9,8 +9,8 @@ mobs:register_mob("animalworld:kangaroo", {
reach = 2,
damage = 2,
hp_min = 25,
hp_max = 35,
armor = 200,
hp_max = 55,
armor = 100,
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.95, 0.5},
visual = "mesh",
mesh = "Kangaroo.b3d",
@ -22,11 +22,11 @@ mobs:register_mob("animalworld:kangaroo", {
walk_velocity = 5,
run_velocity = 5,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = true,
jump_height = 8,
pushable = true,
follow = {"default:grass_3", "default:dry_grass_3"},
follow = {"default:grass_3", "default:dry_grass_3", "ethereal:dry_shrub", "farming:lettuce", "farming:seed_wheat", "default:junglegrass"},
view_range = 10,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
@ -65,7 +65,7 @@ if minetest.get_mapgen_setting("mg_name") ~= "v6" then
end
if minetest.get_modpath("ethereal") then
spawn_on = {"ethereal:grass_grove"}
spawn_on = {"ethereal:grass_grove", "default:desert_sand", "ethereal:dry_dirt"}
end
if not mobs.custom_spawn_animal then
@ -76,6 +76,7 @@ mobs:spawn({
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 5,
max_height = 45,
day_toggle = true,

View File

@ -0,0 +1,107 @@
mobs:register_mob("animalworld:kobra", {
stepheight = 2,
type = "monster",
passive = false,
attack_type = "dogshoot",
dogshoot_switch = 1,
dogshoot_count_max = 12, -- shoot for 10 seconds
dogshoot_count2_max = 3, -- dogfight for 3 seconds
reach = 3,
shoot_interval = 2.2,
arrow = "animalworld:snakepoison",
shoot_offset = 1,
attack_animals = true,
reach = 2,
damage = 8,
hp_min = 20,
hp_max = 60,
armor = 100,
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.95, 0.5},
visual = "mesh",
mesh = "Kobra.b3d",
visual_size = {x = 0.3, y = 0.3},
textures = {
{"texturekobra.png"},
},
sounds = {
random = "animalworld_kobra",
attack = "animalworld_kobra",
},
makes_footstep_sound = false,
view_range = 6,
walk_velocity = 1,
run_velocity = 2,
runaway = false,
jump = false,
jump_height = 0,
stepheight = 2,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
{name = "mobs:leather", chance = 1, min = 0, max = 2},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 3,
animation = {
speed_normal = 60,
stand_start = 0,
stand_end = 100,
walk_start = 250,
walk_end = 350,
punch_start = 150,
punch_end = 200,
-- 50-70 is slide/water idle
},
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
})
if not mobs.custom_spawn_monster then
mobs:spawn({
name = "animalworld:kobra",
nodes = {"default:desert_sandstone", "default:desert_stone", "default:sandstone", "default:dirt_with_rainforest_litter"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
min_height = -30,
max_height = 10,
})
end
mobs:register_egg("animalworld:kobra", ("Cobra"), "akobra.png")
mobs:alias_mob("animalworld:kobra", "animalworld:kobra") -- compatiblity
-- mese arrow (weapon)
mobs:register_arrow("animalworld:snakepoison", {
visual = "sprite",
-- visual = "wielditem",
visual_size = {x = 0.5, y = 0.5},
textures = {"animalworld_snakepoison.png"},
--textures = {""animalworld_snakepoison.png""},
velocity = 6,
-- rotate = 180,
hit_player = function(self, player)
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 2},
}, nil)
end,
hit_mob = function(self, player)
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 2},
}, nil)
end,
hit_node = function(self, pos, node)
end
})

View File

@ -0,0 +1,99 @@
mobs:register_mob("animalworld:lobster", {
stepheight = 1,
type = "animal",
passive = false,
attack_type = "dogfight",
group_attack = true,
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 5,
hp_min = 25,
hp_max = 70,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Lobster.b3d",
textures = {
{"texturelobster.png"},
},
makes_footstep_sound = true,
sounds = {
},
walk_velocity = 0.5,
run_velocity = 1,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark"},
jump = false,
jump_height = 3,
pushable = true,
follow = {"animalworld:rawfish", "mobs_fish:tropical", "mobs:clownfish_raw",
"mobs:bluefish_raw", "fishing:bait_worm", "fishing:clownfish_raw", "fishing:bluewhite_raw", "fishing:exoticfish_raw", "fishing:fish_raw", "fishing:carp_raw", "fishing:perch_raw", "water_life:meat_raw", "fishing:shark_raw", "fishing:pike_raw"},
view_range = 10,
drops = {
{name = "animalworld:raw_athropod", chance = 1, min = 0, max = 2},
},
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible"
},
water_damage = 0,
lava_damage = 5,
air_damage = 1,
light_damage = 0,
fear_height = 2,
animation = {
speed_normal = 50,
stand_start = 0,
stand_end = 100,
walk_start = 100,
walk_end = 200,
punch_start = 200,
punch_end = 300,
die_start = 1, -- we dont have a specific death animation so we will
die_end = 2, -- re-use 2 standing frames at a speed of 1 fps and
die_speed = 1, -- have mob rotate when dying.
die_loop = false,
die_rotate = true,
},
on_rightclick = function(self, clicker)
if mobs:feed_tame(self, clicker, 8, true, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 0, 5, 50, false, nil) then return end
end,
})
local spawn_on = {"default:water_source"}
if minetest.get_mapgen_setting("mg_name") ~= "v6" then
spawn_on = {"default:water_source"}
end
if minetest.get_modpath("ethereal") then
spawn_on = {"default:water_source"}
end
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:lobster",
nodes = {"default:water_source"},
neighbors = spawn_by,
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 10,
day_toggle = false,
})
end
mobs:register_egg("animalworld:lobster", ("Lobster"), "alobster.png")
mobs:alias_mob("animalworld:lobster", "animalworld:lobster") -- compatibility

View File

@ -7,8 +7,8 @@ stepheight = 0.0,
reach = 1,
damage = 1,
hp_min = 50,
hp_max = 60,
armor = 200,
hp_max = 80,
armor = 100,
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.95, 0.7},
visual = "mesh",
mesh = "Manatee.b3d",
@ -50,7 +50,7 @@ stepheight = 0.0,
floats = 0,
follow = {
"default:kelp", "seaweed", "xocean:kelp",
"default:grass", "farming:cucumber", "farming:cabbage"
"default:grass", "farming:cucumber", "farming:cabbage", "xocean:seagrass", "farming:lettuce", "default:junglegrass"
},
view_range = 10,
@ -70,6 +70,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 10,
day_toggle = true,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,79 @@
mobs:register_mob("animalworld:monitor", {
stepheight = 1,
type = "monster",
passive = false,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 8,
hp_min = 20,
hp_max = 55,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Monitor.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"texturemonitor.png"},
},
sounds = {
random = "animalworld_monitor",
attack = "animalworld_monitor",
},
makes_footstep_sound = true,
walk_velocity = 1.5,
run_velocity = 2.5,
runaway = false,
jump = true,
jump_height = 0.5,
stepheight = 1,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 2,
animation = {
speed_normal = 75,
stand_start = 0,
stand_end = 100,
walk_start = 100,
walk_end = 200,
fly_start = 350, -- swim animation
fly_end = 450,
punch_start = 200,
punch_end = 300,
-- 50-70 is slide/water idle
},
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "xocean:fish_edible", "animalworld:chicken_raw", "water_life:meat_raw"
},
view_range = 8,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_monster then
mobs:spawn({
name = "animalworld:monitor",
nodes = {"default:desert_sand"}, {"default:desert_sandstone"}, {"default:sandstone"}, {"ethereal:dry_dirt"}, {"ethereal:fiery_dirt"},
min_light = 14,
interval = 60,
chance = 8000, -- 15000
min_height = 20,
max_height = 45,
day_toggle = true,
})
end
mobs:register_egg("animalworld:monitor", ("Monitor Lizard"), "amonitor.png")

View File

@ -7,10 +7,10 @@ mobs:register_mob("animalworld:moose", {
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 2,
damage = 7,
hp_min = 25,
hp_max = 40,
armor = 200,
hp_max = 60,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Moose.b3d",
@ -29,10 +29,11 @@ mobs:register_mob("animalworld:moose", {
jump = false,
jump_height = 3,
pushable = true,
follow = {"default:apple", "farming:potato"},
follow = {"default:apple", "farming:potato", "farming:melon_slice", "farming:cucumber", "farming:cabbage", "farming:lettuce", "farming:bread"},
view_range = 10,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
{name = "mobs:leather", chance = 1, min = 0, max = 2},
},
water_damage = 0,
lava_damage = 5,
@ -68,7 +69,7 @@ if minetest.get_mapgen_setting("mg_name") ~= "v6" then
end
if minetest.get_modpath("ethereal") then
spawn_on = {"ethereal:grass_grove"}
spawn_on = {"ethereal:grass_grove", "default:dirt_with_grass", "default:dirt_with_coniferous_litter"}
end
if not mobs.custom_spawn_animal then

View File

@ -7,10 +7,10 @@ stepheight = 1,
owner_loyal = true,
attack_npcs = false,
reach = 2,
damage = 2,
damage = 5,
hp_min = 20,
hp_max = 30,
armor = 200,
hp_max = 50,
armor = 100,
collisionbox = {-0.5, -0.01, -0.3, 0.5, 0.1, 0.5},
visual = "mesh",
mesh = "Nandu.b3d",
@ -90,7 +90,7 @@ stepheight = 1,
local spawn_on = {"default:dirt_with_grass"}
if minetest.get_modpath("ethereal") then
spawn_on = {"ethereal:bamboo_dirt", "ethereal:prairie_dirt"}
spawn_on = {"ethereal:bamboo_dirt", "ethereal:prairie_dirt", "default:dirt_with_grass"}
end
@ -101,6 +101,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 10,
max_height = 40,
day_toggle = true,

View File

@ -0,0 +1,83 @@
mobs:register_mob("animalworld:owl", {
stepheight = 3,
type = "monster",
passive = false,
attack_type = "dogfight",
attack_animals = true,
owner_loyal = true,
reach = 2,
damage = 3,
hp_min = 5,
hp_max = 35,
armor = 100,
collisionbox = {-0.3, -0.01, -1, 0.3, 0.3, 0.3},
visual = "mesh",
mesh = "Owl.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"textureowl.png"},
},
sounds = {
random = "animalworld_owl",
},
makes_footstep_sound = false,
walk_velocity = 5,
run_velocity = 5,
fall_speed = 0,
jump = true,
jump_height = 6,
stepheight = 3,
fly = true,
drops = {
{name = "animalworld:chicken_raw", chance = 1, min = 1, max = 1},
{name = "animalworld:chicken_feather", chance = 1, min = 1, max = 1},
},
water_damage = 1,
lava_damage = 4,
light_damage = 0,
fear_height = 0,
animation = {
speed_normal = 100,
stand_start = 0,
stand_end = 90,
walk_start = 400,
walk_end = 500,
fly_start = 400, -- swim animation
fly_end = 500,
punch_start = 200,
punch_end = 300,
-- 50-70 is slide/water idle
},
fly_in = {"air"},
floats = 0,
follow = {
"animalworld:rabbit_raw", "mobs:meat_raw", "animalworld:chicken_raw", "water_life:meat_raw"
},
view_range = 6,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_monster then
mobs:spawn({
name = "animalworld:owl",
nodes = {"default:dirt_with_coniferous_litter"}, {"default:pine_needles"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
min_height = 10,
max_height = 60,
day_toggle = false,
})
end
mobs:register_egg("animalworld:owl", ("Owl"), "aowl.png")

View File

@ -0,0 +1,82 @@
mobs:register_mob("animalworld:puffin", {
stepheight = 3,
type = "animal",
passive = true,
attack_type = "dogfight",
attack_animals = false,
reach = 2,
damage = 1,
hp_min = 5,
hp_max = 35,
armor = 100,
collisionbox = {-0.3, -0.01, -1, 0.3, 0.3, 0.3},
visual = "mesh",
mesh = "Puffin.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"texturepuffin.png"},
},
sounds = {
},
makes_footstep_sound = false,
walk_velocity = 5,
run_velocity = 6,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
fall_speed = 0,
jump = true,
jump_height = 6,
fly = true,
stepheight = 3,
drops = {
{name = "animalworld:chicken_raw", chance = 1, min = 1, max = 1},
{name = "animalworld:chicken_feather", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 0,
animation = {
speed_normal = 130,
stand_start = 0,
stand_end = 100,
walk_start = 150,
walk_end = 250,
fly_start = 150, -- swim animation
fly_end = 250,
-- 50-70 is slide/water idle
},
fly_in = {"air", "default:water_source", "default:river_water_source"},
floats = 0,
follow = {
"animalworld:rawfish", "mobs:clownfish_raw", "mobs:bluefish_raw", "fishing:bait_worm", "fishing:clownfish_raw", "fishing:bluewhite_raw", "fishing:exoticfish_raw", "fishing:fish_raw", "fishing:carp_raw", "fishing:perch_raw", "xocean:fish_edible"
},
view_range = 4,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:puffin",
nodes = {"default:snowblock"}, {"default:ice"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = 0,
max_height = 10,
day_toggle = true,
})
end
mobs:register_egg("animalworld:puffin", ("Puffin"), "apuffin.png")

View File

@ -0,0 +1,96 @@
mobs:register_mob("animalworld:rat", {
type = "animal",
stepheight = 3,
passive = false,
attack_type = "dogfight",
attack_npcs = false,
group_attack = true,
reach = 2,
damage = 3,
hp_min = 5,
hp_max = 35,
armor = 100,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.2, 0.4},
visual = "mesh",
mesh = "Rat.b3d",
textures = {
{"texturerat.png"},
{"texturerat.png"},
},
makes_footstep_sound = true,
sounds = {
random = "animalworld_rat",
attack = "animalworld_rat",
},
walk_velocity = 2,
run_velocity = 3,
jump = true,
jump_height = 6,
pushable = true,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 3},
},
water_damage = 0,
lava_damage = 5,
light_damage = 0,
fear_height = 6,
animation = {
stand_start = 0,
stand_end = 100,
stand_speed = 50,
walk_start = 100,
walk_end = 200,
walk_speed = 130,
punch_start = 250,
punch_end = 350,
punch_speed = 125,
die_start = 1, -- we dont have a specific death animation so we will
die_end = 2, -- re-use 2 standing frames at a speed of 1 fps and
die_speed = 1, -- have mob rotate when dying.
die_loop = false,
die_rotate = true,
},
follow = {"farming:wheat", "farming:beans", "farming:barley", "farming:oat", "farming:rye", "mobs:cheese", "farming:bread", "ethereal:banana_bread"},
view_range = 10,
})
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:rat",
nodes = {"default:stone", "default:mossycobble"},
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 2,
min_height = -100,
max_height = 0,
})
end
mobs:register_egg("animalworld:rat", ("Rat"), "arat.png")
mobs:alias_mob("animalworld:rat", "animalworld:rat") -- compatibility
-- cooked rat, yummy!
minetest.register_craftitem(":animalworld:rat_cooked", {
description = ("Cooked Rodent Meat"),
inventory_image = "animalworld_cooked_rat.png",
on_use = minetest.item_eat(3),
groups = {food_rat = 1, flammable = 2},
})
minetest.register_craft({
type = "cooking",
output = "animalworld:rat_cooked",
recipe = "animalworld:rat",
cooktime = 5,
})

View File

@ -9,8 +9,8 @@ mobs:register_mob("animalworld:reindeer", {
reach = 2,
damage = 2,
hp_min = 25,
hp_max = 30,
armor = 200,
hp_max = 50,
armor = 100,
collisionbox = {-0.6, -0.01, -0.6, 0.6, 0.95, 0.6},
visual = "mesh",
mesh = "Reindeer.b3d",
@ -24,11 +24,11 @@ mobs:register_mob("animalworld:reindeer", {
walk_velocity = 1,
run_velocity = 3,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "player"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine", "player"},
jump = false,
jump_height = 3,
pushable = true,
follow = {"default:apple", "default:permafrost_with_moss"},
follow = {"default:apple", "default:permafrost_with_moss", "ethereal:snowygrass", "ethereal:crystalgrass"},
view_range = 10,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
@ -73,11 +73,11 @@ end
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:reindeer",
nodes = {"default:dirt_with_snow", "default:permafrost_with_moss"},
neighbors = spawn_by,
nodes = {"default:dirt_with_snow", "default:permafrost_with_moss", "ethereal:crystal_dirt"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
active_object_count = 4,
min_height = 20,
max_height = 80,
day_toggle = true,

View File

@ -4,8 +4,8 @@ stepheight = 0.6,
passive = true,
reach = 1,
hp_min = 20,
hp_max = 35,
armor = 200,
hp_max = 55,
armor = 100,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 0.95, 0.4},
visual = "mesh",
mesh = "Seal.b3d",
@ -22,7 +22,7 @@ stepheight = 0.6,
run_velocity = 1,
runaway = true,
runaway = true,
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark"},
runaway_from = {"animalworld:bear", "animalworld:crocodile", "animalworld:tiger", "animalworld:spider", "animalworld:spidermale", "animalworld:shark", "animalworld:hyena", "animalworld:kobra", "animalworld:monitor", "animalworld:snowleopard", "animalworld:volverine"},
jump = false,
stepheight = 1.1,
drops = {
@ -46,7 +46,7 @@ stepheight = 0.6,
floats = 0,
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs_fish:clownfish_set", "mobs_fish:tropical_set", "xocean:fish_edible"
"mobs_fish:clownfish_set", "mobs_fish:tropical_set", "xocean:fish_edible", "mobs:bluefish_raw"
},
view_range = 10,
@ -66,6 +66,7 @@ mobs:spawn({
min_light = 14,
interval = 60,
chance = 8000, -- 15000
active_object_count = 3,
min_height = 0,
max_height = 10,
day_toggle = true,

View File

@ -5,10 +5,10 @@ stepheight = 0.0,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 7,
damage = 14,
hp_min = 30,
hp_max = 75,
armor = 200,
hp_max = 95,
armor = 100,
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.95, 0.7},
visual = "mesh",
mesh = "Shark.b3d",
@ -52,7 +52,7 @@ stepheight = 0.0,
fly_in = {"default:water_source", "default:river_water_source", "default:water_flowing"},
floats = 0,
follow = {
"mobs:meat_raw"
"mobs:meat_raw", "xocean:fish_edible", "ethereal:fish_raw", "mobs:clownfish_raw", "mobs:bluefish_raw", "fishing:bait_worm", "fishing:clownfish_raw", "fishing:bluewhite_raw", "fishing:exoticfish_raw", "fishing:fish_raw", "fishing:carp_raw", "fishing:perch_raw", "water_life:meat_raw", "fishing:shark_raw", "fishing:pike_raw"
},
view_range = 17,

View File

@ -0,0 +1,77 @@
mobs:register_mob("animalworld:snowleopard", {
stepheight = 5,
type = "monster",
passive = false,
attack_type = "dogfight",
attack_animals = true,
reach = 2,
damage = 9,
hp_min = 45,
hp_max = 75,
armor = 100,
collisionbox = {-0.5, -0.01, -0.5, 0.5, 0.95, 0.5},
visual = "mesh",
mesh = "Snowleopard.b3d",
visual_size = {x = 1.0, y = 1.0},
textures = {
{"texturesnowleopard.png"},
},
sounds = {
random = "animalworld_snowleopard",
attack = "animalworld_snowleopard",
},
makes_footstep_sound = true,
walk_velocity = 3,
run_velocity = 4,
runaway = false,
jump = true,
jump_height = 6,
stepheight = 5,
drops = {
{name = "mobs:meat_raw", chance = 1, min = 1, max = 1},
},
water_damage = 0,
lava_damage = 4,
light_damage = 0,
fear_height = 10,
animation = {
speed_normal = 140,
stand_start = 0,
stand_end = 100,
stand_speed = 50,
walk_start = 100,
walk_end = 200,
punch_start = 250,
punch_end = 350,
-- 50-70 is slide/water idle
},
follow = {
"ethereal:fish_raw", "animalworld:rawfish", "mobs_fish:tropical",
"mobs:meat_raw", "animalworld:rabbit_raw", "animalworld:pork_raw", "ethereal:fish_raw", "water_life:meat_raw", "animalworld:chicken_raw"
},
view_range = 15,
on_rightclick = function(self, clicker)
-- feed or tame
if mobs:feed_tame(self, clicker, 4, false, true) then return end
if mobs:protect(self, clicker) then return end
if mobs:capture_mob(self, clicker, 5, 50, 80, false, nil) then return end
end,
})
if not mobs.custom_spawn_animal then
mobs:spawn({
name = "animalworld:snowleopard",
nodes = {"default:snowblock"}, {"default:dirt_with_snow"}, {"default:permafrost"}, {"default:stone"},
min_light = 0,
interval = 60,
chance = 8000, -- 15000
min_height = 60,
max_height = 300,
})
end
mobs:register_egg("animalworld:snowleopard", ("Snow Leopard"), "asnowleopard.png")

Some files were not shown because too many files have changed in this diff Show More