write something there
This commit is contained in:
commit
b4b6c08f4f
8546 changed files with 309825 additions and 0 deletions
21
mods/animalia/.luacheckrc
Normal file
21
mods/animalia/.luacheckrc
Normal file
|
@ -0,0 +1,21 @@
|
|||
max_line_length = 120
|
||||
|
||||
globals = {
|
||||
"minetest",
|
||||
"VoxelArea",
|
||||
"mob_core",
|
||||
"creatura",
|
||||
"animalia",
|
||||
"farming",
|
||||
"mcl_player",
|
||||
"player_api",
|
||||
"armor"
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
"vector",
|
||||
"ItemStack",
|
||||
table = {fields = {"copy"}}
|
||||
}
|
||||
|
||||
ignore = {"212/self", "212/this"}
|
21
mods/animalia/LICENSE
Normal file
21
mods/animalia/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022 ElCeejo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
882
mods/animalia/api/api.lua
Normal file
882
mods/animalia/api/api.lua
Normal file
|
@ -0,0 +1,882 @@
|
|||
---------
|
||||
-- API --
|
||||
---------
|
||||
|
||||
-- Math --
|
||||
|
||||
local abs = math.abs
|
||||
local atan2 = math.atan2
|
||||
local cos = math.cos
|
||||
local deg = math.deg
|
||||
local min = math.min
|
||||
local pi = math.pi
|
||||
local pi2 = pi * 2
|
||||
local rad = math.rad
|
||||
local random = math.random
|
||||
local sin = math.sin
|
||||
local sqrt = math.sqrt
|
||||
|
||||
|
||||
local function diff(a, b) -- Get difference between 2 angles
|
||||
return atan2(sin(b - a), cos(b - a))
|
||||
end
|
||||
|
||||
local function interp_angle(a, b, w)
|
||||
local cs = (1 - w) * cos(a) + w * cos(b)
|
||||
local sn = (1 - w) * sin(a) + w * sin(b)
|
||||
return atan2(sn, cs)
|
||||
end
|
||||
|
||||
local function lerp_step(a, b, dtime, rate)
|
||||
return min(dtime * rate, abs(diff(a, b)) % (pi2))
|
||||
end
|
||||
|
||||
local function clamp(val, _min, _max)
|
||||
if val < _min then
|
||||
val = _min
|
||||
elseif _max < val then
|
||||
val = _max
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
-- Vector Math --
|
||||
|
||||
local vec_add, vec_dir, vec_dist, vec_divide, vec_len, vec_multi, vec_normal,
|
||||
vec_round, vec_sub = vector.add, vector.direction, vector.distance, vector.divide,
|
||||
vector.length, vector.multiply, vector.normalize, vector.round, vector.subtract
|
||||
|
||||
local dir2yaw = minetest.dir_to_yaw
|
||||
local yaw2dir = minetest.yaw_to_dir
|
||||
|
||||
------------
|
||||
-- Common --
|
||||
------------
|
||||
|
||||
function animalia.get_average_pos(vectors)
|
||||
local sum = {x = 0, y = 0, z = 0}
|
||||
for _, vec in pairs(vectors) do sum = vec_add(sum, vec) end
|
||||
return vec_divide(sum, #vectors)
|
||||
end
|
||||
|
||||
function animalia.correct_name(str)
|
||||
if str then
|
||||
if str:match(":") then str = str:split(":")[2] end
|
||||
return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " "))
|
||||
end
|
||||
end
|
||||
|
||||
---------------------
|
||||
-- Local Utilities --
|
||||
---------------------
|
||||
|
||||
local function activate_nametag(self)
|
||||
self.nametag = self:recall("nametag") or nil
|
||||
if not self.nametag then return end
|
||||
self.object:set_properties({
|
||||
nametag = self.nametag,
|
||||
nametag_color = "#FFFFFF"
|
||||
})
|
||||
end
|
||||
|
||||
animalia.animate_player = {}
|
||||
|
||||
if minetest.get_modpath("default")
|
||||
and minetest.get_modpath("player_api") then
|
||||
animalia.animate_player = player_api.set_animation
|
||||
elseif minetest.get_modpath("mcl_player") then
|
||||
animalia.animate_player = mcl_player.player_set_animation
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Dynamic Animation --
|
||||
-----------------------
|
||||
|
||||
function animalia.rotate_to_pitch(self)
|
||||
local rot = self.object:get_rotation()
|
||||
if self._anim == "fly" then
|
||||
local vel = vec_normal(self.object:get_velocity())
|
||||
local step = min(self.dtime * 5, abs(diff(rot.x, vel.y)) % (pi2))
|
||||
local n_rot = interp_angle(rot.x, vel.y, step)
|
||||
self.object:set_rotation({
|
||||
x = clamp(n_rot, -0.75, 0.75),
|
||||
y = rot.y,
|
||||
z = rot.z
|
||||
})
|
||||
elseif rot.x ~= 0 then
|
||||
self.object:set_rotation({
|
||||
x = 0,
|
||||
y = rot.y,
|
||||
z = rot.z
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.move_head(self, tyaw, pitch)
|
||||
local data = self.head_data
|
||||
if not data then return end
|
||||
local yaw = self.object:get_yaw()
|
||||
local pitch_offset = data.pitch_correction or 0
|
||||
local bone = data.bone or "Head.CTRL"
|
||||
local _, rot = self.object:get_bone_position(bone)
|
||||
if not rot then return end
|
||||
local n_yaw = (tyaw ~= yaw and diff(tyaw, yaw) / 2) or 0
|
||||
if abs(deg(n_yaw)) > 45 then n_yaw = 0 end
|
||||
local dir = yaw2dir(n_yaw)
|
||||
dir.y = pitch or 0
|
||||
local n_pitch = (sqrt(dir.x^2 + dir.y^2) / dir.z)
|
||||
if abs(deg(n_pitch)) > 45 then n_pitch = 0 end
|
||||
if self.dtime then
|
||||
local yaw_w = lerp_step(rad(rot.z), tyaw, self.dtime, 3)
|
||||
n_yaw = interp_angle(rad(rot.z), n_yaw, yaw_w)
|
||||
local rad_offset = rad(pitch_offset)
|
||||
local pitch_w = lerp_step(rad(rot.x), n_pitch + rad_offset, self.dtime, 3)
|
||||
n_pitch = interp_angle(rad(rot.x), n_pitch + rad_offset, pitch_w)
|
||||
end
|
||||
local pitch_max = pitch_offset + 45
|
||||
local pitch_min = pitch_offset - 45
|
||||
self.object:set_bone_position(bone, data.offset,
|
||||
{x = clamp(deg(n_pitch), pitch_min, pitch_max), y = 0, z = clamp(deg(n_yaw), -45, 45)})
|
||||
end
|
||||
|
||||
function animalia.head_tracking(self)
|
||||
if not self.head_data then return end
|
||||
-- Calculate Head Position
|
||||
local yaw = self.object:get_yaw()
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local y_dir = yaw2dir(yaw)
|
||||
local offset_h = self.head_data.pivot_h
|
||||
local offset_v = self.head_data.pivot_v
|
||||
pos = {
|
||||
x = pos.x + y_dir.x * offset_h,
|
||||
y = pos.y + offset_v,
|
||||
z = pos.z + y_dir.z * offset_h
|
||||
}
|
||||
local vel = self.object:get_velocity()
|
||||
if vec_len(vel) > 2 then
|
||||
self.head_tracking = nil
|
||||
animalia.move_head(self, yaw, 0)
|
||||
return
|
||||
end
|
||||
local player = self.head_tracking
|
||||
local plyr_pos = player and player:get_pos()
|
||||
if plyr_pos then
|
||||
plyr_pos.y = plyr_pos.y + 1.4
|
||||
local dir = vec_dir(pos, plyr_pos)
|
||||
local tyaw = dir2yaw(dir)
|
||||
if abs(diff(yaw, tyaw)) > pi / 10
|
||||
and self._anim == "stand" then
|
||||
self:turn_to(tyaw, 1)
|
||||
end
|
||||
animalia.move_head(self, tyaw, dir.y)
|
||||
return
|
||||
elseif self:timer(6)
|
||||
and random(4) < 2 then
|
||||
|
||||
local players = creatura.get_nearby_players(self, 6)
|
||||
self.head_tracking = #players > 0 and players[random(#players)]
|
||||
end
|
||||
animalia.move_head(self, yaw, 0)
|
||||
|
||||
end
|
||||
|
||||
---------------
|
||||
-- Utilities --
|
||||
---------------
|
||||
|
||||
function animalia.alias_mob(old_mob, new_mob)
|
||||
minetest.register_entity(":" .. old_mob, {
|
||||
on_activate = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
minetest.add_entity(pos, new_mob)
|
||||
self.object:remove()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
------------------------
|
||||
-- Environment Access --
|
||||
------------------------
|
||||
|
||||
function animalia.has_shared_owner(obj1, obj2)
|
||||
local ent1 = obj1 and obj1:get_luaentity()
|
||||
local ent2 = obj2 and obj2:get_luaentity()
|
||||
if ent1
|
||||
and ent2 then
|
||||
return ent1.owner and ent2.owner and ent1.owner == ent2.owner
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function animalia.get_attack_score(entity, attack_list)
|
||||
local pos = entity.stand_pos
|
||||
if not pos then return end
|
||||
|
||||
local order = entity.order or "wander"
|
||||
if order ~= "wander" then return 0 end
|
||||
|
||||
local target = entity._target or (entity.attacks_players and creatura.get_nearby_player(entity))
|
||||
local tgt_pos = target and target:get_pos()
|
||||
|
||||
if not tgt_pos
|
||||
or not entity:is_pos_safe(tgt_pos)
|
||||
or (target:is_player()
|
||||
and minetest.is_creative_enabled(target:get_player_name())) then
|
||||
target = creatura.get_nearby_object(entity, attack_list)
|
||||
tgt_pos = target and target:get_pos()
|
||||
end
|
||||
|
||||
if not tgt_pos then entity._target = nil return 0 end
|
||||
|
||||
if target == entity.object then entity._target = nil return 0 end
|
||||
|
||||
if animalia.has_shared_owner(entity.object, target) then entity._target = nil return 0 end
|
||||
|
||||
local dist = vec_dist(pos, tgt_pos)
|
||||
local score = (entity.tracking_range - dist) / entity.tracking_range
|
||||
|
||||
if entity.trust
|
||||
and target:is_player()
|
||||
and entity.trust[target:get_player_name()] then
|
||||
local trust = entity.trust[target:get_player_name()]
|
||||
local trust_score = ((entity.max_trust or 10) - trust) / (entity.max_trust or 10)
|
||||
|
||||
score = score - trust_score
|
||||
end
|
||||
|
||||
entity._target = target
|
||||
return score * 0.5, {entity, target}
|
||||
end
|
||||
|
||||
function animalia.get_nearby_mate(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local objects = creatura.get_nearby_objects(self, self.name)
|
||||
for _, object in ipairs(objects) do
|
||||
local obj_pos = object and object:get_pos()
|
||||
local ent = obj_pos and object:get_luaentity()
|
||||
if obj_pos
|
||||
and ent.growth_scale == 1
|
||||
and ent.gender ~= self.gender
|
||||
and ent.breeding then
|
||||
return object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.find_collision(self, dir)
|
||||
local pos = self.object:get_pos()
|
||||
local pos2 = vec_add(pos, vec_multi(dir, 16))
|
||||
local ray = minetest.raycast(pos, pos2, false, false)
|
||||
for pointed_thing in ray do
|
||||
if pointed_thing.type == "node" then
|
||||
return pointed_thing.under
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function animalia.random_drop_item(self, item, chance)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
if random(chance) < 2 then
|
||||
local object = minetest.add_item(pos, ItemStack(item))
|
||||
object:add_velocity({
|
||||
x = random(-2, 2),
|
||||
y = 1.5,
|
||||
z = random(-2, 2)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
---------------
|
||||
-- Particles --
|
||||
---------------
|
||||
|
||||
function animalia.particle_spawner(pos, texture, type, min_pos, max_pos)
|
||||
type = type or "float"
|
||||
min_pos = min_pos or vec_sub(pos, 1)
|
||||
max_pos = max_pos or vec_add(pos, 1)
|
||||
if type == "float" then
|
||||
minetest.add_particlespawner({
|
||||
amount = 16,
|
||||
time = 0.25,
|
||||
minpos = min_pos,
|
||||
maxpos = max_pos,
|
||||
minvel = {x = 0, y = 0.2, z = 0},
|
||||
maxvel = {x = 0, y = 0.25, z = 0},
|
||||
minexptime = 0.75,
|
||||
maxexptime = 1,
|
||||
minsize = 4,
|
||||
maxsize = 4,
|
||||
texture = texture,
|
||||
glow = 1,
|
||||
})
|
||||
elseif type == "splash" then
|
||||
minetest.add_particlespawner({
|
||||
amount = 6,
|
||||
time = 0.25,
|
||||
minpos = {x = pos.x - 7/16, y = pos.y + 0.6, z = pos.z - 7/16},
|
||||
maxpos = {x = pos.x + 7/16, y = pos.y + 0.6, z = pos.z + 7/16},
|
||||
minvel = {x = -1, y = 2, z = -1},
|
||||
maxvel = {x = 1, y = 5, z = 1},
|
||||
minacc = {x = 0, y = -9.81, z = 0},
|
||||
maxacc = {x = 0, y = -9.81, z = 0},
|
||||
minsize = 2,
|
||||
maxsize = 4,
|
||||
collisiondetection = true,
|
||||
texture = texture,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.add_food_particle(self, item_name)
|
||||
local pos, yaw = self.object:get_pos(), self.object:get_yaw()
|
||||
if not pos then return end
|
||||
local head = self.head_data
|
||||
local offset_h = (head and head.pivot_h) or self.width
|
||||
local offset_v = (head and head.pivot_v) or self.height
|
||||
local head_pos = {
|
||||
x = pos.x + sin(yaw) * -offset_h,
|
||||
y = pos.y + offset_v,
|
||||
z = pos.z + cos(yaw) * offset_h
|
||||
}
|
||||
local def = minetest.registered_items[item_name]
|
||||
local image = def.inventory_image
|
||||
if def.tiles then
|
||||
image = def.tiles[1].name or def.tiles[1]
|
||||
end
|
||||
if image then
|
||||
local crop = "^[sheet:4x4:" .. random(0,3) .. "," .. random(0,3)
|
||||
minetest.add_particlespawner({
|
||||
pos = head_pos,
|
||||
time = 0.5,
|
||||
amount = 12,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vel = {min = {x = -1, y = 1, z = -1}, max = {x = 1, y = 2, z = 1}},
|
||||
acc = {x = 0, y = -9.8, z = 0},
|
||||
size = {min = 1, max = 2},
|
||||
texture = image .. crop
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.add_break_particle(pos)
|
||||
pos = vec_round(pos)
|
||||
local def = creatura.get_node_def(pos)
|
||||
local texture = (def.tiles and def.tiles[1]) or def.inventory_image
|
||||
texture = texture .. "^[resize:8x8"
|
||||
minetest.add_particlespawner({
|
||||
amount = 6,
|
||||
time = 0.1,
|
||||
minpos = {
|
||||
x = pos.x,
|
||||
y = pos.y - 0.49,
|
||||
z = pos.z
|
||||
},
|
||||
maxpos = {
|
||||
x = pos.x,
|
||||
y = pos.y - 0.49,
|
||||
z = pos.z
|
||||
},
|
||||
minvel = {x=-1, y=1, z=-1},
|
||||
maxvel = {x=1, y=2, z=1},
|
||||
minacc = {x=0, y=-5, z=0},
|
||||
maxacc = {x=0, y=-9, z=0},
|
||||
minexptime = 1,
|
||||
maxexptime = 1.5,
|
||||
minsize = 1,
|
||||
maxsize = 2,
|
||||
collisiondetection = true,
|
||||
vertical = false,
|
||||
texture = texture,
|
||||
})
|
||||
end
|
||||
|
||||
----------
|
||||
-- Mobs --
|
||||
----------
|
||||
|
||||
function animalia.death_func(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.get_dropped_food(self, item, radius)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
local objects = minetest.get_objects_inside_radius(pos, radius or self.tracking_range)
|
||||
for _, object in ipairs(objects) do
|
||||
local ent = object:get_luaentity()
|
||||
if ent
|
||||
and ent.name == "__builtin:item"
|
||||
and ent.itemstring
|
||||
and ((item and ent.itemstring:match(item))
|
||||
or self:follow_item(ItemStack(ent.itemstring))) then
|
||||
return object, object:get_pos()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.eat_dropped_item(self, item)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
local food = item or animalia.get_dropped_food(self, nil, self.width + 1)
|
||||
|
||||
local food_ent = food and food:get_luaentity()
|
||||
if food_ent then
|
||||
local food_pos = food:get_pos()
|
||||
|
||||
local stack = ItemStack(food_ent.itemstring)
|
||||
if stack
|
||||
and stack:get_count() > 1 then
|
||||
stack:take_item()
|
||||
food_ent.itemstring = stack:to_string()
|
||||
else
|
||||
food:remove()
|
||||
end
|
||||
|
||||
self.object:set_yaw(dir2yaw(vec_dir(pos, food_pos)))
|
||||
animalia.add_food_particle(self, stack:get_name())
|
||||
|
||||
if self.on_eat_drop then
|
||||
self:on_eat_drop()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.protect_from_despawn(self)
|
||||
self._despawn = self:memorize("_despawn", false)
|
||||
self.despawn_after = self:memorize("despawn_after", false)
|
||||
end
|
||||
|
||||
function animalia.despawn_inactive_mob(self)
|
||||
local os_time = os.time()
|
||||
self._last_active = self:recall("_last_active")
|
||||
if self._last_active
|
||||
and self.despawn_after then
|
||||
local last_active = self._last_active
|
||||
if os_time - last_active > self.despawn_after then
|
||||
self.object:remove()
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.set_nametag(self, clicker)
|
||||
local plyr_name = clicker and clicker:get_player_name()
|
||||
if not plyr_name then return end
|
||||
local item = clicker:get_wielded_item()
|
||||
if item
|
||||
and item:get_name() ~= "animalia:nametag" then
|
||||
return
|
||||
end
|
||||
local name = item:get_meta():get_string("name")
|
||||
if not name
|
||||
or name == "" then
|
||||
return
|
||||
end
|
||||
self.nametag = self:memorize("nametag", name)
|
||||
self.despawn_after = self:memorize("despawn_after", false)
|
||||
activate_nametag(self)
|
||||
if not minetest.is_creative_enabled(plyr_name) then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function animalia.initialize_api(self)
|
||||
-- Set Gender
|
||||
self.gender = self:recall("gender") or nil
|
||||
if not self.gender then
|
||||
local genders = {"male", "female"}
|
||||
self.gender = self:memorize("gender", genders[random(2)])
|
||||
-- Reset Texture ID
|
||||
self.texture_no = nil
|
||||
end
|
||||
|
||||
-- Taming/Breeding
|
||||
self.food = self:recall("food") or 0
|
||||
self.gotten = self:recall("gotten") or false
|
||||
self.breeding = false
|
||||
self.breeding_cooldown = self:recall("breeding_cooldown") or 0
|
||||
|
||||
-- Textures/Scale
|
||||
activate_nametag(self)
|
||||
if self.growth_scale then
|
||||
self:memorize("growth_scale", self.growth_scale) -- This is for spawning children
|
||||
end
|
||||
self.growth_scale = self:recall("growth_scale") or 1
|
||||
self:set_scale(self.growth_scale)
|
||||
local child_textures = self.growth_scale < 0.8 and self.child_textures
|
||||
local textures = (not child_textures and self[self.gender .. "_textures"]) or self.textures
|
||||
if child_textures then
|
||||
if not self.texture_no
|
||||
or self.texture_no > #child_textures then
|
||||
self.texture_no = random(#child_textures)
|
||||
end
|
||||
self:set_texture(self.texture_no, child_textures)
|
||||
elseif textures then
|
||||
if not self.texture_no then
|
||||
self.texture_no = random(#textures)
|
||||
end
|
||||
self:set_texture(self.texture_no, textures)
|
||||
end
|
||||
if self.growth_scale < 0.8
|
||||
and self.child_mesh then
|
||||
self.object:set_properties({
|
||||
mesh = self.child_mesh
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.step_timers(self)
|
||||
local breed_cd = self.breeding_cooldown or 30
|
||||
local trust_cd = self.trust_cooldown or 0
|
||||
self.breeding_cooldown = (breed_cd > 0 and breed_cd - self.dtime) or 0
|
||||
self.trust_cooldown = (trust_cd > 0 and trust_cd - self.dtime) or 0
|
||||
if self.breeding
|
||||
and self.breeding_cooldown <= 30 then
|
||||
self.breeding = false
|
||||
end
|
||||
self:memorize("breeding_cooldown", self.breeding_cooldown)
|
||||
self:memorize("trust_cooldown", self.trust_cooldown)
|
||||
self:memorize("_last_active", os.time())
|
||||
end
|
||||
|
||||
function animalia.do_growth(self, interval)
|
||||
if self.growth_scale
|
||||
and self.growth_scale < 0.9 then
|
||||
if self:timer(interval) then
|
||||
self.growth_scale = self.growth_scale + 0.1
|
||||
self:set_scale(self.growth_scale)
|
||||
if self.growth_scale < 0.8
|
||||
and self.child_textures then
|
||||
local tex_no = self.texture_no
|
||||
if not self.child_textures[tex_no] then
|
||||
tex_no = 1
|
||||
end
|
||||
self:set_texture(tex_no, self.child_textures)
|
||||
elseif self.growth_scale == 0.8 then
|
||||
if self.child_mesh then self:set_mesh() end
|
||||
if self.male_textures
|
||||
and self.female_textures then
|
||||
if #self.child_textures == 1 then
|
||||
self.texture_no = random(#self[self.gender .. "_textures"])
|
||||
end
|
||||
self:set_texture(self.texture_no, self[self.gender .. "_textures"])
|
||||
else
|
||||
if #self.child_textures == 1 then
|
||||
self.texture_no = random(#self.textures)
|
||||
end
|
||||
self:set_texture(self.texture_no, self.textures)
|
||||
end
|
||||
if self.on_grown then
|
||||
self:on_grown()
|
||||
end
|
||||
end
|
||||
self:memorize("growth_scale", self.growth_scale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.random_sound(self)
|
||||
if self:timer(8)
|
||||
and random(4) < 2 then
|
||||
self:play_sound("random")
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.add_trust(self, player, amount)
|
||||
if self.trust_cooldown > 0 then return end
|
||||
self.trust_cooldown = 60
|
||||
local plyr_name = player:get_player_name()
|
||||
local trust = self.trust[plyr_name] or 0
|
||||
if trust > 4 then return end
|
||||
self.trust[plyr_name] = trust + (amount or 1)
|
||||
self:memorize("trust", self.trust)
|
||||
end
|
||||
|
||||
function animalia.feed(self, clicker, tame, breed)
|
||||
local yaw = self.object:get_yaw()
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local name = clicker:is_player() and clicker:get_player_name()
|
||||
local item, item_name = self:follow_wielded_item(clicker)
|
||||
if item_name then
|
||||
-- Eat Animation
|
||||
local head = self.head_data
|
||||
local offset_h = (head and head.pivot_h) or 0.5
|
||||
local offset_v = (head and head.pivot_v) or 0.5
|
||||
local head_pos = {
|
||||
x = pos.x + sin(yaw) * -offset_h,
|
||||
y = pos.y + offset_v,
|
||||
z = pos.z + cos(yaw) * offset_h
|
||||
}
|
||||
local def = minetest.registered_items[item_name]
|
||||
if def.inventory_image then
|
||||
minetest.add_particlespawner({
|
||||
pos = head_pos,
|
||||
time = 0.1,
|
||||
amount = 3,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vel = {min = {x = -1, y = 3, z = -1}, max = {x = 1, y = 4, z = 1}},
|
||||
acc = {x = 0, y = -9.8, z = 0},
|
||||
size = {min = 2, max = 4},
|
||||
texture = def.inventory_image
|
||||
})
|
||||
end
|
||||
-- Increase Health
|
||||
local feed_no = (self.feed_no or 0) + 1
|
||||
local max_hp = self.max_health
|
||||
local hp = self.hp
|
||||
hp = hp + (max_hp / 5)
|
||||
if hp > max_hp then hp = max_hp end
|
||||
self.hp = hp
|
||||
-- Tame/Breed
|
||||
if feed_no >= 5 then
|
||||
feed_no = 0
|
||||
if tame then
|
||||
self.owner = self:memorize("owner", name)
|
||||
minetest.add_particlespawner({
|
||||
pos = {min = vec_sub(pos, self.width), max = vec_add(pos, self.width)},
|
||||
time = 0.1,
|
||||
amount = 12,
|
||||
vel = {min = {x = 0, y = 3, z = 0}, max = {x = 0, y = 4, z = 0}},
|
||||
size = {min = 4, max = 6},
|
||||
glow = 16,
|
||||
texture = "creatura_particle_green.png"
|
||||
})
|
||||
end
|
||||
if breed then
|
||||
if self.breeding then return false end
|
||||
if self.breeding_cooldown <= 0 then
|
||||
self.breeding = true
|
||||
self.breeding_cooldown = 60
|
||||
animalia.particle_spawner(pos, "heart.png", "float")
|
||||
end
|
||||
end
|
||||
self._despawn = self:memorize("_despawn", false)
|
||||
self.despawn_after = self:memorize("despawn_after", false)
|
||||
end
|
||||
self.feed_no = feed_no
|
||||
-- Take item
|
||||
if not minetest.is_creative_enabled(name) then
|
||||
item:take_item()
|
||||
clicker:set_wielded_item(item)
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.mount(self, player, params)
|
||||
if not creatura.is_alive(player)
|
||||
or (player:get_attach()
|
||||
and player:get_attach() ~= self.object) then
|
||||
return
|
||||
end
|
||||
local plyr_name = player:get_player_name()
|
||||
if (player:get_attach()
|
||||
and player:get_attach() == self.object)
|
||||
or not params then
|
||||
player:set_detach()
|
||||
player:set_properties({
|
||||
visual_size = {
|
||||
x = 1,
|
||||
y = 1
|
||||
}
|
||||
})
|
||||
player:set_eye_offset()
|
||||
if minetest.get_modpath("player_api") then
|
||||
animalia.animate_player(player, "stand", 30)
|
||||
if player_api.player_attached then
|
||||
player_api.player_attached[plyr_name] = false
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
if minetest.get_modpath("player_api") then
|
||||
player_api.player_attached[plyr_name] = true
|
||||
end
|
||||
self.rider = player
|
||||
player:set_attach(self.object, "Torso", params.pos, params.rot)
|
||||
player:set_eye_offset({x = 0, y = 20, z = 5}, {x = 0, y = 15, z = 15})
|
||||
self:clear_utility()
|
||||
minetest.after(0.4, function()
|
||||
animalia.animate_player(player, "sit" , 30)
|
||||
end)
|
||||
end
|
||||
|
||||
function animalia.punch(self, puncher, ...)
|
||||
if self.hp <= 0 then return end
|
||||
creatura.basic_punch_func(self, puncher, ...)
|
||||
self._puncher = puncher
|
||||
if self.flee_puncher
|
||||
and (self:get_utility() or "") ~= "animalia:flee_from_target" then
|
||||
self:clear_utility()
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.find_crop(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
local nodes = minetest.find_nodes_in_area(vec_sub(pos, 6), vec_add(pos, 6), "group:crop") or {}
|
||||
if #nodes < 1 then return end
|
||||
return nodes[math.random(#nodes)]
|
||||
end
|
||||
|
||||
function animalia.eat_crop(self, pos)
|
||||
local node_name = minetest.get_node(pos).name
|
||||
local new_name = node_name:sub(1, #node_name - 1) .. (tonumber(node_name:sub(-1)) or 2) - 1
|
||||
local new_def = minetest.registered_nodes[new_name]
|
||||
if not new_def then return false end
|
||||
local p2 = new_def.place_param2 or 1
|
||||
minetest.set_node(pos, {name = new_name, param2 = p2})
|
||||
animalia.add_food_particle(self, new_name)
|
||||
return true
|
||||
end
|
||||
|
||||
function animalia.eat_turf(mob, pos)
|
||||
for name, sub_name in pairs(mob.consumable_nodes) do
|
||||
if minetest.get_node(pos).name == name then
|
||||
--add_break_particle(turf_pos)
|
||||
minetest.set_node(pos, {name = sub_name})
|
||||
mob.collected = mob:memorize("collected", false)
|
||||
--creatura.action_idle(mob, 1, "eat")
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------
|
||||
-- Spawning --
|
||||
--------------
|
||||
|
||||
animalia.registered_biome_groups = {}
|
||||
|
||||
function animalia.register_biome_group(name, def)
|
||||
animalia.registered_biome_groups[name] = def
|
||||
animalia.registered_biome_groups[name].biomes = {}
|
||||
end
|
||||
|
||||
local function assign_biome_group(name)
|
||||
local def = minetest.registered_biomes[name]
|
||||
local turf = def.node_top
|
||||
local heat = def.heat_point or 0
|
||||
local humidity = def.humidity_point or 50
|
||||
local y_min = def.y_min
|
||||
local y_max = def.y_max
|
||||
for group, params in pairs(animalia.registered_biome_groups) do -- k, v in pairs
|
||||
if name:find(params.name_kw or "")
|
||||
and turf and turf:find(params.turf_kw or "")
|
||||
and heat >= params.min_heat
|
||||
and heat <= params.max_heat
|
||||
and humidity >= params.min_humidity
|
||||
and humidity <= params.max_humidity
|
||||
and (not params.min_height or y_min >= params.min_height)
|
||||
and (not params.max_height or y_max <= params.max_height) then
|
||||
table.insert(animalia.registered_biome_groups[group].biomes, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
for name in pairs(minetest.registered_biomes) do
|
||||
assign_biome_group(name)
|
||||
end
|
||||
end)
|
||||
|
||||
animalia.register_biome_group("temperate", {
|
||||
name_kw = "",
|
||||
turf_kw = "grass",
|
||||
min_heat = 45,
|
||||
max_heat = 70,
|
||||
min_humidity = 0,
|
||||
max_humidity = 50
|
||||
})
|
||||
|
||||
animalia.register_biome_group("urban", {
|
||||
name_kw = "",
|
||||
turf_kw = "grass",
|
||||
min_heat = 0,
|
||||
max_heat = 100,
|
||||
min_humidity = 0,
|
||||
max_humidity = 100
|
||||
})
|
||||
|
||||
animalia.register_biome_group("grassland", {
|
||||
name_kw = "",
|
||||
turf_kw = "grass",
|
||||
min_heat = 45,
|
||||
max_heat = 90,
|
||||
min_humidity = 0,
|
||||
max_humidity = 80
|
||||
})
|
||||
|
||||
animalia.register_biome_group("boreal", {
|
||||
name_kw = "",
|
||||
turf_kw = "litter",
|
||||
min_heat = 10,
|
||||
max_heat = 55,
|
||||
min_humidity = 0,
|
||||
max_humidity = 80
|
||||
})
|
||||
|
||||
animalia.register_biome_group("ocean", {
|
||||
name_kw = "ocean",
|
||||
turf_kw = "",
|
||||
min_heat = 0,
|
||||
max_heat = 100,
|
||||
min_humidity = 0,
|
||||
max_humidity = 100,
|
||||
max_height = 0
|
||||
})
|
||||
|
||||
animalia.register_biome_group("swamp", {
|
||||
name_kw = "",
|
||||
turf_kw = "",
|
||||
min_heat = 55,
|
||||
max_heat = 90,
|
||||
min_humidity = 55,
|
||||
max_humidity = 90,
|
||||
max_height = 10,
|
||||
min_height = -20
|
||||
})
|
||||
|
||||
animalia.register_biome_group("tropical", {
|
||||
name_kw = "",
|
||||
turf_kw = "litter",
|
||||
min_heat = 70,
|
||||
max_heat = 90,
|
||||
min_humidity = 65,
|
||||
max_humidity = 90
|
||||
})
|
||||
|
||||
animalia.register_biome_group("cave", {
|
||||
name_kw = "under",
|
||||
turf_kw = "",
|
||||
min_heat = 0,
|
||||
max_heat = 100,
|
||||
min_humidity = 0,
|
||||
max_humidity = 100,
|
||||
max_height = 5
|
||||
})
|
||||
|
||||
animalia.register_biome_group("common", {
|
||||
name_kw = "",
|
||||
turf_kw = "",
|
||||
min_heat = 25,
|
||||
max_heat = 75,
|
||||
min_humidity = 20,
|
||||
max_humidity = 80,
|
||||
min_height = 1
|
||||
})
|
251
mods/animalia/api/lasso.lua
Normal file
251
mods/animalia/api/lasso.lua
Normal file
|
@ -0,0 +1,251 @@
|
|||
-----------
|
||||
-- Lasso --
|
||||
-----------
|
||||
|
||||
local abs = math.abs
|
||||
|
||||
local vec_add, vec_dir, vec_dist, vec_len = vector.add, vector.direction, vector.distance, vector.length
|
||||
local dir2rot = vector.dir_to_rotation
|
||||
|
||||
-- Entities --
|
||||
|
||||
local using_lasso = {}
|
||||
|
||||
minetest.register_entity("animalia:lasso_entity", {
|
||||
visual = "mesh",
|
||||
mesh = "animalia_lasso_entity.b3d",
|
||||
textures = {"animalia_lasso_entity.png"},
|
||||
pointable = false,
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
end,
|
||||
_scale = 1,
|
||||
on_step = function(self)
|
||||
local pos, parent = self.object:get_pos(), (self.object:get_attach() or self._attached)
|
||||
local pointed_ent = self._point_to and self._point_to:get_luaentity()
|
||||
local point_to = self._point_to and self._point_to:get_pos()
|
||||
if not pos or not parent or not point_to then self.object:remove() return end
|
||||
if type(parent) == "string" then
|
||||
parent = minetest.get_player_by_name(parent)
|
||||
if not parent then self.object:remove() return end
|
||||
local tgt_pos = parent:get_pos()
|
||||
tgt_pos.y = tgt_pos.y + 1
|
||||
point_to.y = point_to.y + pointed_ent.height * 0.5
|
||||
local dist = vec_dist(pos, tgt_pos)
|
||||
if dist > 0.5 then
|
||||
self.object:set_pos(tgt_pos)
|
||||
else
|
||||
self.object:move_to(tgt_pos)
|
||||
end
|
||||
self.object:set_rotation(dir2rot(vec_dir(tgt_pos, point_to)))
|
||||
elseif parent.x then
|
||||
point_to.y = point_to.y + pointed_ent.height * 0.5
|
||||
self.object:set_rotation(dir2rot(vec_dir(pos, point_to)))
|
||||
else
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local size = vec_dist(pos, point_to)
|
||||
if abs(size - self._scale) > 0.1 then
|
||||
self.object:set_properties({
|
||||
visual_size = {x = 1, y = 1, z = size}
|
||||
})
|
||||
self._scale = size
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
local function remove_from_fence(self)
|
||||
local pos = self.object:get_pos()
|
||||
local mob = self._mob and self._mob:get_luaentity()
|
||||
if not mob then
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
mob._lassod_to = nil
|
||||
mob:forget("_lassod_to")
|
||||
mob._lasso_ent:remove()
|
||||
local dirs = {
|
||||
{x = 0.5, y = 0, z = 0},
|
||||
{x = -0.5, y = 0, z = 0},
|
||||
{x = 0, y = 0.5, z = 0},
|
||||
{x = 0, y = -0.5, z = 0},
|
||||
{x = 0, y = 0, z = 0.5},
|
||||
{x = 0, y = 0, z = -0.5}
|
||||
}
|
||||
for i = 1, 6 do
|
||||
local i_pos = vec_add(pos, dirs[i])
|
||||
if not creatura.get_node_def(i_pos).walkable then
|
||||
minetest.add_item(i_pos, "animalia:lasso")
|
||||
break
|
||||
end
|
||||
end
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
minetest.register_entity("animalia:tied_lasso_entity", {
|
||||
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
|
||||
visual = "cube",
|
||||
visual_size = {x = 0.3, y = 0.3},
|
||||
mesh = "model",
|
||||
textures = {
|
||||
"animalia_tied_lasso_entity.png",
|
||||
"animalia_tied_lasso_entity.png",
|
||||
"animalia_tied_lasso_entity.png",
|
||||
"animalia_tied_lasso_entity.png",
|
||||
"animalia_tied_lasso_entity.png",
|
||||
"animalia_tied_lasso_entity.png",
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
end,
|
||||
on_step = function(self)
|
||||
local mob = self._mob and self._mob:get_luaentity()
|
||||
if not mob then remove_from_fence(self) return end
|
||||
end,
|
||||
on_rightclick = remove_from_fence,
|
||||
on_punch = remove_from_fence
|
||||
})
|
||||
|
||||
-- API --
|
||||
|
||||
local function add_lasso(self, origin)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local object = minetest.add_entity(pos, "animalia:lasso_entity")
|
||||
local ent = object and object:get_luaentity()
|
||||
if not ent then return end
|
||||
-- Attachment point of entity
|
||||
ent._attached = origin
|
||||
if type(origin) ~= "string" then
|
||||
--local player = minetest.get_player_by_name(origin)
|
||||
--object:set_attach(player)
|
||||
--else
|
||||
object:set_pos(origin)
|
||||
end
|
||||
self._lassod_to = origin
|
||||
ent._point_to = self.object
|
||||
self:memorize("_lassod_to", origin)
|
||||
return object
|
||||
end
|
||||
|
||||
local function get_rope_velocity(pos1, pos2, dist)
|
||||
local force = dist / 10
|
||||
local vel = vector.new((pos2.x - pos1.x) * force, ((pos2.y - pos1.y) / (24 + dist)), (pos2.z - pos1.z) * force)
|
||||
return vel
|
||||
end
|
||||
|
||||
function animalia.initialize_lasso(self)
|
||||
self._lassod_to = self:recall("_lassod_to") or self:recall("lasso_origin")
|
||||
if self._lassod_to then
|
||||
local origin = self._lassod_to
|
||||
if type(origin) == "table"
|
||||
and minetest.get_item_group(minetest.get_node(origin).name, "fence") > 0 then
|
||||
local object = minetest.add_entity(origin, "animalia:tied_lasso_entity")
|
||||
object:get_luaentity()._mob = self.object
|
||||
self._lasso_ent = add_lasso(self, origin)
|
||||
elseif type(origin) == "string" then
|
||||
self._lassod_to = origin
|
||||
self._lasso_ent = add_lasso(self, origin)
|
||||
else
|
||||
self:forget("_lassod_to")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function animalia.update_lasso_effects(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not creatura.is_alive(self) then return end
|
||||
if self._lassod_to then
|
||||
local lasso = self._lassod_to
|
||||
self._lasso_ent = self._lasso_ent or add_lasso(self, lasso)
|
||||
if type(lasso) == "string" then
|
||||
using_lasso[lasso] = self
|
||||
local name = lasso
|
||||
lasso = minetest.get_player_by_name(lasso)
|
||||
if lasso then
|
||||
if lasso:get_wielded_item():get_name() ~= "animalia:lasso" then
|
||||
using_lasso[name] = nil
|
||||
self._lasso_ent:remove()
|
||||
self._lasso_ent = nil
|
||||
self._lassod_to = nil
|
||||
self:forget("_lassod_to")
|
||||
return
|
||||
end
|
||||
local lasso_pos = lasso:get_pos()
|
||||
local dist = vec_dist(pos, lasso_pos)
|
||||
local vel = self.object:get_velocity()
|
||||
if not vel or dist < 8 and self.touching_ground then return end
|
||||
if vec_len(vel) < 8 then
|
||||
self.object:add_velocity(get_rope_velocity(pos, lasso_pos, dist))
|
||||
end
|
||||
return
|
||||
end
|
||||
elseif type(lasso) == "table" then
|
||||
local dist = vec_dist(pos, lasso)
|
||||
local vel = self.object:get_velocity()
|
||||
if not vel or dist < 8 and self.touching_ground then return end
|
||||
if vec_len(vel) < 8 then
|
||||
self.object:add_velocity(get_rope_velocity(pos, lasso, dist))
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
if self._lasso_ent then
|
||||
self._lasso_ent:remove()
|
||||
self._lasso_ent = nil
|
||||
self._lassod_to = nil
|
||||
self:forget("_lassod_to")
|
||||
end
|
||||
end
|
||||
|
||||
-- Item
|
||||
|
||||
minetest.register_craftitem("animalia:lasso", {
|
||||
description = "Lasso",
|
||||
inventory_image = "animalia_lasso.png",
|
||||
on_secondary_use = function(_, placer, pointed)
|
||||
local ent = pointed.ref and pointed.ref:get_luaentity()
|
||||
if ent
|
||||
and (ent.name:match("^animalia:")
|
||||
or ent.name:match("^monstrum:")) then
|
||||
if not ent.catch_with_lasso then return end
|
||||
local name = placer:get_player_name()
|
||||
if not ent._lassod_to
|
||||
and not using_lasso[name] then
|
||||
using_lasso[name] = ent
|
||||
ent._lassod_to = name
|
||||
ent:memorize("_lassod_to", name)
|
||||
elseif ent._lassod_to
|
||||
and ent._lassod_to == name then
|
||||
using_lasso[name] = nil
|
||||
ent._lassod_to = nil
|
||||
ent:forget("_lassod_to")
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type == "node" then
|
||||
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
||||
if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then
|
||||
local name = placer:get_player_name()
|
||||
local ent = using_lasso[name]
|
||||
if ent
|
||||
and ent._lassod_to
|
||||
and ent._lassod_to == name then
|
||||
using_lasso[name] = nil
|
||||
ent._lasso_ent:set_detach()
|
||||
ent._lasso_ent:set_pos(pos)
|
||||
ent._lasso_ent:get_luaentity()._attached = pos
|
||||
ent._lassod_to = pos
|
||||
ent:memorize("_lassod_to", pos)
|
||||
local fence_obj = minetest.add_entity(pos, "animalia:tied_lasso_entity")
|
||||
fence_obj:get_luaentity()._mob = ent.object
|
||||
fence_obj:get_luaentity()._lasso_obj = ent._lasso_ent
|
||||
itemstack:take_item(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
})
|
82
mods/animalia/api/legacy_convert.lua
Normal file
82
mods/animalia/api/legacy_convert.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
--------------------------------------
|
||||
-- Convert Better Fauna to Animalia --
|
||||
--------------------------------------
|
||||
|
||||
for i = 1, #animalia.mobs do
|
||||
local new_mob = animalia.mobs[i]
|
||||
local old_mob = "better_fauna:" .. new_mob:split(":")[2]
|
||||
minetest.register_entity(":" .. old_mob, {
|
||||
on_activate = mob_core.on_activate
|
||||
})
|
||||
minetest.register_alias_force("better_fauna:spawn_" .. new_mob:split(":")[2],
|
||||
"animalia:spawn_" .. new_mob:split(":")[2])
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local mobs = minetest.luaentities
|
||||
for _, mob in pairs(mobs) do
|
||||
if mob
|
||||
and mob.name:match("better_fauna:") then
|
||||
local pos = mob.object:get_pos()
|
||||
if not pos then return end
|
||||
if mob.name:find("lasso_fence_ent") then
|
||||
if pos then
|
||||
minetest.add_entity(pos, "animalia:lasso_fence_ent")
|
||||
end
|
||||
mob.object:remove()
|
||||
elseif mob.name:find("lasso_visual") then
|
||||
if pos then
|
||||
minetest.add_entity(pos, "animalia:lasso_visual")
|
||||
end
|
||||
mob.object:remove()
|
||||
end
|
||||
for i = 1, #animalia.mobs do
|
||||
local ent = animalia.mobs[i]
|
||||
local new_name = ent:split(":")[2]
|
||||
local old_name = mob.name:split(":")[2]
|
||||
if new_name == old_name then
|
||||
if pos then
|
||||
local new_mob = minetest.add_entity(pos, ent)
|
||||
local mem = nil
|
||||
if mob.memory then
|
||||
mem = mob.memory
|
||||
end
|
||||
minetest.after(0.1, function()
|
||||
if mem then
|
||||
new_mob:get_luaentity().memory = mem
|
||||
new_mob:get_luaentity():on_activate(new_mob, nil, dtime)
|
||||
end
|
||||
end)
|
||||
end
|
||||
mob.object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- Tools
|
||||
|
||||
minetest.register_alias_force("better_fauna:net", "animalia:net")
|
||||
minetest.register_alias_force("better_fauna:lasso", "animalia:lasso")
|
||||
minetest.register_alias_force("better_fauna:cat_toy", "animalia:cat_toy")
|
||||
minetest.register_alias_force("better_fauna:saddle", "animalia:saddle")
|
||||
minetest.register_alias_force("better_fauna:shears", "animalia:shears")
|
||||
|
||||
-- Drops
|
||||
|
||||
minetest.register_alias_force("better_fauna:beef_raw", "animalia:beef_raw")
|
||||
minetest.register_alias_force("better_fauna:beef_cooked", "animalia:beef_cooked")
|
||||
minetest.register_alias_force("better_fauna:bucket_milk", "animalia:bucket_milk")
|
||||
minetest.register_alias_force("better_fauna:leather", "animalia:leather")
|
||||
minetest.register_alias_force("better_fauna:chicken_egg", "animalia:chicken_egg")
|
||||
minetest.register_alias_force("better_fauna:chicken_raw", "animalia:poultry_raw")
|
||||
minetest.register_alias_force("better_fauna:chicken_cooked", "animalia:poultry_cooked")
|
||||
minetest.register_alias_force("better_fauna:feather", "animalia:feather")
|
||||
minetest.register_alias_force("better_fauna:mutton_raw", "animalia:mutton_raw")
|
||||
minetest.register_alias_force("better_fauna:mutton_cooked", "animalia:mutton_cooked")
|
||||
minetest.register_alias_force("better_fauna:porkchop_raw", "animalia:porkchop_raw")
|
||||
minetest.register_alias_force("better_fauna:porkchop_cooked", "animalia:porkchop_cooked")
|
||||
minetest.register_alias_force("better_fauna:turkey_raw", "animalia:poultry_raw")
|
||||
minetest.register_alias_force("better_fauna:turkey_cooked", "animalia:poultry_cooked")
|
528
mods/animalia/api/libri.lua
Normal file
528
mods/animalia/api/libri.lua
Normal file
|
@ -0,0 +1,528 @@
|
|||
-----------
|
||||
-- Libri --
|
||||
-----------
|
||||
|
||||
local libri = {}
|
||||
|
||||
local path = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local color = minetest.colorize
|
||||
|
||||
local libri_bg = {
|
||||
"formspec_version[3]",
|
||||
"size[16,10]",
|
||||
"background[-0.7,-0.5;17.5,11.5;animalia_libri_bg.png]"
|
||||
}
|
||||
|
||||
local libri_btn_next = "image_button[15,9;1,1;animalia_libri_icon_next.png;btn_next;;true;false]"
|
||||
|
||||
local libri_btn_last = "image_button[1,9;1,1;animalia_libri_icon_last.png;btn_last;;true;false]"
|
||||
|
||||
local libri_drp_font_scale = "dropdown[17,0;0.75,0.5;drp_font_scale;0.25,0.5,0.75,1;1]"
|
||||
|
||||
local function correct_string(str)
|
||||
if str then
|
||||
if str:match(":") then str = str:split(":")[2] end
|
||||
return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " "))
|
||||
end
|
||||
end
|
||||
|
||||
local pages = {}
|
||||
|
||||
local generate_mobs = {
|
||||
["animalia:bat"] = "Bat",
|
||||
["animalia:cat"] = "Cat",
|
||||
["animalia:chicken"] = "Chicken",
|
||||
["animalia:cow"] = "Cow",
|
||||
["animalia:opossum"] = "Opossum",
|
||||
["animalia:owl"] = "Owl",
|
||||
["animalia:tropical_fish"] = "Tropical Fish",
|
||||
["animalia:fox"] = "Fox",
|
||||
["animalia:frog"] = "Frog",
|
||||
["animalia:grizzly_bear"] = "Grizzly Bear",
|
||||
["animalia:horse"] = "Horse",
|
||||
["animalia:pig"] = "Pig",
|
||||
["animalia:rat"] = "Rat",
|
||||
["animalia:reindeer"] = "Reindeer",
|
||||
["animalia:sheep"] = "Sheep",
|
||||
["animalia:song_bird"] = "Song Bird",
|
||||
["animalia:turkey"] = "Turkey",
|
||||
["animalia:wolf"] = "Wolf",
|
||||
}
|
||||
|
||||
|
||||
local spawn_biomes = {
|
||||
["animalia:bat"] = "cave",
|
||||
["animalia:cat"] = "urban",
|
||||
["animalia:chicken"] = "tropical",
|
||||
["animalia:cow"] = "grassland",
|
||||
["animalia:opossum"] = "temperate",
|
||||
["animalia:owl"] = "temperate",
|
||||
["animalia:tropical_fish"] = "ocean",
|
||||
["animalia:fox"] = "boreal",
|
||||
["animalia:frog"] = "swamp",
|
||||
["animalia:grizzly_bear"] = "boreal",
|
||||
["animalia:horse"] = "grassland",
|
||||
["animalia:pig"] = "temperate",
|
||||
["animalia:rat"] = "urban",
|
||||
["animalia:reindeer"] = "boreal",
|
||||
["animalia:sheep"] = "grassland",
|
||||
["animalia:song_bird"] = "temperate",
|
||||
["animalia:turkey"] = "boreal",
|
||||
["animalia:wolf"] = "boreal",
|
||||
}
|
||||
|
||||
-----------
|
||||
-- Pages --
|
||||
-----------
|
||||
|
||||
|
||||
local function get_spawn_biomes(name)
|
||||
local biomes = asuna.features.animals[name] or {}
|
||||
return (#biomes > 0) and biomes or {"grassland"}
|
||||
end
|
||||
|
||||
local function can_lasso(name)
|
||||
return tostring(minetest.registered_entities[name].catch_with_lasso or false)
|
||||
end
|
||||
|
||||
local function can_net(name)
|
||||
return tostring(minetest.registered_entities[name].catch_with_net or false)
|
||||
end
|
||||
|
||||
local function max_health(name)
|
||||
return minetest.registered_entities[name].max_health or 20
|
||||
end
|
||||
|
||||
local function mob_textures(name, mesh_no)
|
||||
local def = minetest.registered_entities[name]
|
||||
local textures = def.textures
|
||||
if def.male_textures
|
||||
or def.female_textures then
|
||||
textures = {unpack(def.male_textures), unpack(def.female_textures)}
|
||||
end
|
||||
if def.mesh_textures then
|
||||
textures = def.mesh_textures[mesh_no or 1]
|
||||
end
|
||||
return textures
|
||||
end
|
||||
|
||||
local biome_cubes = {}
|
||||
|
||||
local function generate_page(mob)
|
||||
local name = mob:split(":")[2]
|
||||
local def = minetest.registered_entities[mob]
|
||||
if not def then return end
|
||||
local page = {
|
||||
{ -- Info
|
||||
element_type = "label",
|
||||
center_text = true,
|
||||
font_size = 20,
|
||||
offset = {x = 8, y = 1.5},
|
||||
file = "animalia_libri_" .. name .. ".txt"
|
||||
},
|
||||
{ -- Image
|
||||
element_type = "model",
|
||||
offset = {x = 1.5, y = 1.5},
|
||||
size = {x = 5, y = 5},
|
||||
mesh_iter = def.meshes and 1,
|
||||
texture_iter = 1,
|
||||
text = "mesh;" .. def.mesh .. ";" .. mob_textures(mob)[1] .. ";-30,225;false;false;0,0;0"
|
||||
},
|
||||
{ -- Spawn Biome
|
||||
element_type = "image",
|
||||
offset = {x = 0.825, y = 8.15},
|
||||
size = {x = 1, y = 1},
|
||||
biome_iter = 1,
|
||||
text = biome_cubes[get_spawn_biomes(mob)[1]]
|
||||
},
|
||||
{ -- Biome Label
|
||||
element_type = "tooltip",
|
||||
offset = {x = 0.825, y = 8.15},
|
||||
size = {x = 1, y = 1},
|
||||
biome_iter = 1,
|
||||
text = correct_string(get_spawn_biomes(mob)[1])
|
||||
},
|
||||
libri.render_element({ -- Health Icon
|
||||
element_type = "image",
|
||||
offset = {x = 2.535, y = 8.15},
|
||||
size = {x = 1, y = 1},
|
||||
text = "animalia_libri_health_fg.png"
|
||||
}),
|
||||
libri.render_element({ -- Health Amount
|
||||
element_type = "label",
|
||||
offset = {x = 3.25, y = 9},
|
||||
text = "x" .. max_health(mob) / 2
|
||||
}),
|
||||
libri.render_element({ -- Lasso Icon
|
||||
element_type = "item_image",
|
||||
offset = {x = 4.25, y = 8.15},
|
||||
size = {x = 1, y = 1},
|
||||
text = "animalia:lasso"
|
||||
}),
|
||||
libri.render_element({ -- Lasso Indication Icon
|
||||
element_type = "image",
|
||||
offset = {x = 4.75, y = 8.75},
|
||||
size = {x = 0.5, y = 0.5},
|
||||
text = "animalia_libri_" .. can_lasso(mob) .. "_icon.png"
|
||||
}),
|
||||
libri.render_element({ -- Net Icon
|
||||
element_type = "item_image",
|
||||
offset = {x = 6, y = 8.15},
|
||||
size = {x = 1, y = 1},
|
||||
text = "animalia:net"
|
||||
}),
|
||||
libri.render_element({ -- Net Indication Icon
|
||||
element_type = "image",
|
||||
offset = {x = 6.5, y = 8.75},
|
||||
size = {x = 0.5, y = 0.5},
|
||||
text = "animalia_libri_" .. can_net(mob) .. "_icon.png"
|
||||
}),
|
||||
libri.render_element({ -- Styling
|
||||
element_type = "image",
|
||||
offset = {x = -0.7, y = -0.5},
|
||||
size = {x = 17.5, y = 11.5},
|
||||
text = "animalia_libri_info_fg.png"
|
||||
})
|
||||
}
|
||||
pages[mob] = page
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
-- Register Biome Cubes
|
||||
for name, def in pairs(minetest.registered_biomes) do
|
||||
if def.node_top then
|
||||
local tiles = {
|
||||
"unknown_node.png",
|
||||
"unknown_node.png",
|
||||
"unknown_node.png"
|
||||
}
|
||||
local n_def = minetest.registered_nodes[def.node_top]
|
||||
if n_def then
|
||||
local def_tiles = table.copy(n_def.tiles or n_def.textures)
|
||||
for i, tile in ipairs(def_tiles) do
|
||||
if tile.name then
|
||||
def_tiles[i] = tile.name
|
||||
end
|
||||
end
|
||||
tiles = (#def_tiles > 0 and def_tiles) or tiles
|
||||
end
|
||||
biome_cubes[name] = minetest.inventorycube(tiles[1], tiles[3], tiles[3])
|
||||
else
|
||||
biome_cubes[name] = minetest.inventorycube("unknown_node.png", "unknown_node.png", "unknown_node.png")
|
||||
end
|
||||
end
|
||||
pages = {
|
||||
["home_1"] = {
|
||||
{ -- Info
|
||||
element_type = "label",
|
||||
center_text = true,
|
||||
font_size = 24,
|
||||
offset = {x = 0, y = 1.5},
|
||||
file = "animalia_libri_home.txt"
|
||||
},
|
||||
{
|
||||
element_type = "mobs",
|
||||
start_iter = 0,
|
||||
offset = {x = 10.25, y = 1.5}
|
||||
}
|
||||
},
|
||||
["home_2"] = {
|
||||
{
|
||||
element_type = "mobs",
|
||||
start_iter = 4,
|
||||
offset = {x = 1.75, y = 1.5}
|
||||
}
|
||||
},
|
||||
["home_3"] = {
|
||||
{
|
||||
element_type = "mobs",
|
||||
start_iter = 12,
|
||||
offset = {x = 1.75, y = 1.5}
|
||||
}
|
||||
}
|
||||
}
|
||||
for mob in pairs(generate_mobs) do
|
||||
generate_page(mob)
|
||||
end
|
||||
end)
|
||||
|
||||
---------
|
||||
-- API --
|
||||
---------
|
||||
|
||||
local function get_item_list(list, offset_x, offset_y) -- Creates a visual list of items for Libri formspecs
|
||||
local size = 1 / ((#list < 3 and #list) or 3)
|
||||
if size < 0.45 then size = 0.45 end
|
||||
local spacing = size * 0.5
|
||||
local total_scale = size + spacing
|
||||
local max_horiz = 3
|
||||
local form = ""
|
||||
for i, item in ipairs(list) do
|
||||
local vert_multi = math.floor((i - 1) / max_horiz)
|
||||
local horz_multi = (total_scale * max_horiz) * vert_multi
|
||||
local pos_x = offset_x + ((total_scale * i) - horz_multi)
|
||||
local pos_y = offset_y + (total_scale * vert_multi )
|
||||
form = form .. "item_image[" .. pos_x .. "," .. pos_y .. ";" .. size .. "," .. size .. ";" .. item .. "]"
|
||||
end
|
||||
return form
|
||||
end
|
||||
|
||||
function libri.generate_list(meta, offset, start_iter)
|
||||
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
|
||||
local i = 0
|
||||
local elements = ""
|
||||
local offset_x = offset.x
|
||||
local offset_y = offset.y
|
||||
for mob in pairs(chapters) do
|
||||
if not mob then break end
|
||||
i = i + 1
|
||||
if i > start_iter then
|
||||
local mob_name = mob:split(":")[2]
|
||||
local offset_txt = offset_x .. "," .. offset_y
|
||||
local element = "button[" .. offset_txt .. ";4,1;btn_" .. mob_name .. ";" .. correct_string(mob_name) .. "]"
|
||||
elements = elements .. element
|
||||
offset_y = offset_y + 2
|
||||
if offset_y > 7.5 then
|
||||
offset_x = offset_x + 8.5
|
||||
if offset_x > 10.25 then
|
||||
return elements
|
||||
end
|
||||
offset_y = 1.5
|
||||
end
|
||||
end
|
||||
end
|
||||
return elements
|
||||
end
|
||||
|
||||
function libri.render_element(def, meta, playername)
|
||||
local chapters = (meta and minetest.deserialize(meta:get_string("chapters"))) or {}
|
||||
local chap_no = 0
|
||||
for _ in pairs(chapters) do
|
||||
chap_no = chap_no + 1
|
||||
end
|
||||
local offset_x = def.offset.x
|
||||
local offset_y = def.offset.y
|
||||
local form = ""
|
||||
-- Add text
|
||||
if def.element_type == "label" then
|
||||
local font_size_x = (animalia.libri_font_size[playername] or 1)
|
||||
local font_size = (def.font_size or 16) * font_size_x
|
||||
if def.file then
|
||||
local filename = path .. "/libri/" .. def.file
|
||||
local file = io.open(filename)
|
||||
if file then
|
||||
local text = ""
|
||||
for line in file:lines() do
|
||||
text = text .. line .. "\n"
|
||||
end
|
||||
local total_offset = (offset_x + (0.35 - 0.35 * font_size_x)) .. "," .. offset_y
|
||||
form = form ..
|
||||
"hypertext[" .. total_offset .. ";8,9;text;<global color=#000000 size="..
|
||||
font_size .. " halign=center>" .. text .. "]"
|
||||
file:close()
|
||||
end
|
||||
else
|
||||
form = form .. "style_type[label;font_size=" .. font_size .. "]"
|
||||
local line = def.text
|
||||
form = form .. "label[" .. offset_x .. "," .. offset_y .. ";" .. color("#000000", line .. "\n") .. "]"
|
||||
end
|
||||
elseif def.element_type == "mobs" then
|
||||
form = form .. libri.generate_list(meta, def.offset, def.start_iter)
|
||||
if chap_no > def.start_iter + 4 then form = form .. libri_btn_next end
|
||||
if def.start_iter > 3 then form = form .. libri_btn_last end
|
||||
else
|
||||
-- Add Images/Interaction
|
||||
local render_element = false
|
||||
if def.unlock_key
|
||||
and #chapters > 0 then
|
||||
for _, chapter in ipairs(chapters) do
|
||||
if chapter
|
||||
and chapter == def.unlock_key then
|
||||
render_element = true
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif not def.unlock_key then
|
||||
render_element = true
|
||||
end
|
||||
if render_element then
|
||||
local offset = def.offset.x .. "," .. def.offset.y
|
||||
local size = def.size.x .. "," .. def.size.y
|
||||
form = form .. def.element_type .. "[" .. offset .. ";" .. size .. ";" .. def.text .. "]"
|
||||
end
|
||||
end
|
||||
return form
|
||||
end
|
||||
|
||||
local function get_page(key, meta, playername)
|
||||
local form = table.copy(libri_bg)
|
||||
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
|
||||
local chap_no = 0
|
||||
for _ in pairs(chapters) do
|
||||
chap_no = chap_no + 1
|
||||
end
|
||||
local page = pages[key]
|
||||
for _, element in ipairs(page) do
|
||||
if type(element) == "table" then
|
||||
local element_rendered = libri.render_element(element, meta, playername)
|
||||
table.insert(form, element_rendered)
|
||||
else
|
||||
table.insert(form, element)
|
||||
end
|
||||
end
|
||||
table.insert(form, "style[drp_font_scale;noclip=true]")
|
||||
table.insert(form, libri_drp_font_scale)
|
||||
table.insert(form, "style[drp_font_scale;noclip=true]")
|
||||
local def = minetest.registered_entities[key]
|
||||
if def then
|
||||
if def.follow then
|
||||
table.insert(form, get_item_list(def.follow, 12.45, 8.05))
|
||||
end
|
||||
if def.drops then
|
||||
local drops = {}
|
||||
for i = 1, #def.drops do
|
||||
table.insert(drops, def.drops[i].name)
|
||||
end
|
||||
table.insert(form, get_item_list(drops, 8, 8.05))
|
||||
end
|
||||
end
|
||||
return table.concat(form, "")
|
||||
end
|
||||
|
||||
-- Iterate through Animal textures and Biomes
|
||||
|
||||
local libri_players = {}
|
||||
|
||||
local function iterate_libri_images()
|
||||
for page, elements in pairs(pages) do
|
||||
if page ~= "home" then
|
||||
for _, info in ipairs(elements) do
|
||||
if info.texture_iter then
|
||||
local def = minetest.registered_entities[page]
|
||||
local textures = mob_textures(page, info.mesh_iter)
|
||||
|
||||
local tex_i = info.texture_iter
|
||||
info.texture_iter = (textures[tex_i + 1] and tex_i + 1) or 1
|
||||
|
||||
local mesh_i = info.mesh_iter
|
||||
if info.texture_iter < 2 then -- Only iterate mesh if all textures have been shown
|
||||
info.mesh_iter = def.meshes and ((def.meshes[mesh_i + 1] and mesh_i + 1) or 1)
|
||||
textures = mob_textures(page, info.mesh_iter)
|
||||
end
|
||||
|
||||
local mesh = (info.mesh_iter and def.meshes[info.mesh_iter]) or def.mesh
|
||||
info.text = "mesh;" .. mesh .. ";" .. textures[info.texture_iter] .. ";-30,225;false;false;0,0;0]"
|
||||
end
|
||||
if info.biome_iter then
|
||||
local mobname = page:split(":")[2]
|
||||
local biomes = asuna.features.animals[mobname] or {}
|
||||
if biomes[info.biome_iter + 1] then
|
||||
info.biome_iter = info.biome_iter + 1
|
||||
else
|
||||
info.biome_iter = 1
|
||||
end
|
||||
local spawn_biome = biomes[info.biome_iter] or "grassland"
|
||||
if info.element_type == "image" then
|
||||
info.text = biome_cubes[spawn_biome]
|
||||
else
|
||||
info.text = correct_string(asuna.biomes[spawn_biome].name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for name, page in pairs(libri_players) do
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player
|
||||
and spawn_biomes[page] then
|
||||
local meta = player:get_wielded_item():get_meta()
|
||||
minetest.show_formspec(name, "animalia:libri_" .. page:split(":")[2], get_page(page, meta, name))
|
||||
end
|
||||
end
|
||||
minetest.after(2, iterate_libri_images)
|
||||
end
|
||||
|
||||
iterate_libri_images()
|
||||
|
||||
-- Craftitem
|
||||
|
||||
minetest.register_craftitem("animalia:libri_animalia", {
|
||||
description = "Libri Animalia",
|
||||
inventory_image = "animalia_libri_animalia.png",
|
||||
stack_max = 1,
|
||||
groups = {book = 1},
|
||||
|
||||
on_place = function(itemstack, player)
|
||||
local meta = itemstack:get_meta()
|
||||
if meta:get_string("pages") ~= "" then meta:set_string("pages", "") end
|
||||
local name = player:get_player_name()
|
||||
minetest.show_formspec(name, "animalia:libri_home_1", get_page("home_1", meta, name))
|
||||
libri_players[name] = "home_1"
|
||||
end,
|
||||
on_secondary_use = function(itemstack, player, pointed)
|
||||
local meta = itemstack:get_meta()
|
||||
if meta:get_string("pages") ~= "" then meta:set_string("pages", "") end
|
||||
local chapters = minetest.deserialize(meta:get_string("chapters")) or {}
|
||||
if pointed
|
||||
and pointed.type == "object" then
|
||||
local ent = pointed.ref and pointed.ref:get_luaentity()
|
||||
if ent
|
||||
and pages[ent.name]
|
||||
and not chapters[ent.name] then
|
||||
chapters[ent.name] = true
|
||||
itemstack:get_meta():set_string("chapters", minetest.serialize(chapters))
|
||||
player:set_wielded_item(itemstack)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
minetest.show_formspec(name, "animalia:libri_home_1", get_page("home_1", meta, name))
|
||||
libri_players[name] = "home_1"
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local plyr_name = player:get_player_name()
|
||||
local wielded_item = player:get_wielded_item()
|
||||
local meta = wielded_item:get_meta()
|
||||
if formname:match("animalia:libri_") then
|
||||
for page in pairs(pages) do
|
||||
if not page:match("^home") then
|
||||
local name = page:split(":")[2]
|
||||
if fields["btn_" .. name] then
|
||||
minetest.show_formspec(plyr_name, "animalia:libri_" .. name, get_page(page, meta, plyr_name))
|
||||
libri_players[plyr_name] = page
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if fields.btn_next then
|
||||
local current_no = tonumber(formname:sub(-1))
|
||||
local page = "home_" .. current_no + 1
|
||||
if pages[page] then
|
||||
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
|
||||
libri_players[plyr_name] = page
|
||||
return true
|
||||
end
|
||||
end
|
||||
if fields.btn_last then
|
||||
local current_no = tonumber(formname:sub(-1))
|
||||
local page = "home_" .. current_no - 1
|
||||
if pages[page] then
|
||||
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
|
||||
libri_players[plyr_name] = page
|
||||
return true
|
||||
end
|
||||
end
|
||||
if fields.drp_font_scale then
|
||||
animalia.libri_font_size[plyr_name] = fields.drp_font_scale
|
||||
local page = libri_players[plyr_name]
|
||||
if not page then return end
|
||||
minetest.show_formspec(plyr_name, "animalia:libri_" .. page, get_page(page, meta, plyr_name))
|
||||
end
|
||||
if fields.quit or fields.key_enter then
|
||||
libri_players[plyr_name] = nil
|
||||
end
|
||||
end
|
||||
end)
|
2065
mods/animalia/api/mob_ai.lua
Normal file
2065
mods/animalia/api/mob_ai.lua
Normal file
File diff suppressed because it is too large
Load diff
409
mods/animalia/api/spawning.lua
Normal file
409
mods/animalia/api/spawning.lua
Normal file
|
@ -0,0 +1,409 @@
|
|||
--------------
|
||||
-- Spawning --
|
||||
--------------
|
||||
|
||||
local random = math.random
|
||||
|
||||
local function table_contains(tbl, val)
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local common_spawn_chance = tonumber(minetest.settings:get("animalia_common_chance")) or 60000
|
||||
|
||||
local ambient_spawn_chance = tonumber(minetest.settings:get("animalia_ambient_chance")) or 9000
|
||||
|
||||
local pest_spawn_chance = tonumber(minetest.settings:get("animalia_pest_chance")) or 3000
|
||||
|
||||
local predator_spawn_chance = tonumber(minetest.settings:get("animalia_predator_chance")) or 45000
|
||||
|
||||
-- Get Biomes -- already happens via Asuna/biomes.lua
|
||||
|
||||
--[[local chicken_biomes = {}
|
||||
|
||||
local frog_biomes = {}
|
||||
|
||||
local pig_biomes = {}
|
||||
|
||||
local function insert_all(tbl, tbl2)
|
||||
for i = 1, #tbl2 do
|
||||
table.insert(tbl, tbl2[i])
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
insert_all(chicken_biomes, animalia.registered_biome_groups["grassland"].biomes)
|
||||
insert_all(chicken_biomes, animalia.registered_biome_groups["tropical"].biomes)
|
||||
insert_all(pig_biomes, animalia.registered_biome_groups["temperate"].biomes)
|
||||
insert_all(pig_biomes, animalia.registered_biome_groups["boreal"].biomes)
|
||||
insert_all(frog_biomes, animalia.registered_biome_groups["swamp"].biomes)
|
||||
insert_all(frog_biomes, animalia.registered_biome_groups["tropical"].biomes)
|
||||
end)]]
|
||||
|
||||
creatura.register_abm_spawn("animalia:grizzly_bear", {
|
||||
chance = predator_spawn_chance,
|
||||
min_height = -1,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 1,
|
||||
biomes = asuna.features.animals.grizzly_bear,
|
||||
nodes = {"group:sand","group:soil","group:snowy"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:chicken", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 3,
|
||||
max_group = 5,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.chicken,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:cat", {
|
||||
chance = common_spawn_chance,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 2,
|
||||
biomes = asuna.features.animals.cat,
|
||||
nodes = {"group:soil"},
|
||||
neighbors = {"group:wood"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:cow", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 3,
|
||||
max_group = 4,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.cow,
|
||||
nodes = {"group:soil"},
|
||||
neighbors = {"air", "group:grass", "group:flora"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:fox", {
|
||||
chance = predator_spawn_chance,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 2,
|
||||
biomes = asuna.features.animals.fox,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:horse", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 3,
|
||||
max_group = 4,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.horse,
|
||||
nodes = {"group:soil"},
|
||||
neighbors = {"air", "group:grass", "group:flora"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:rat", {
|
||||
chance = pest_spawn_chance,
|
||||
interval = 60,
|
||||
min_height = -1,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 3,
|
||||
spawn_in_nodes = true,
|
||||
biomes = asuna.features.animals.rat,
|
||||
nodes = {"group:crop"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:owl", {
|
||||
chance = predator_spawn_chance,
|
||||
interval = 60,
|
||||
min_height = 3,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 1,
|
||||
spawn_cap = 1,
|
||||
biomes = asuna.features.animals.owl,
|
||||
nodes = {"group:leaves"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:opossum", {
|
||||
chance = predator_spawn_chance,
|
||||
interval = 60,
|
||||
min_height = -1,
|
||||
max_height = 31000,
|
||||
min_group = 1,
|
||||
max_group = 2,
|
||||
biomes = asuna.features.animals.opossum,
|
||||
nodes = {"group:soil", "group:leaves"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:pig", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 2,
|
||||
max_group = 3,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.pig,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:reindeer", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 6,
|
||||
max_group = 8,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.reindeer,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:sheep", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 3,
|
||||
max_group = 6,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.sheep,
|
||||
nodes = {"group:soil"},
|
||||
neighbors = {"air", "group:grass", "group:flora"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:turkey", {
|
||||
chance = common_spawn_chance,
|
||||
spawn_active = true,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 3,
|
||||
max_group = 4,
|
||||
spawn_cap = 3,
|
||||
biomes = asuna.features.animals.turkey,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:wolf", {
|
||||
chance = predator_spawn_chance,
|
||||
min_height = 0,
|
||||
max_height = 31000,
|
||||
min_group = 2,
|
||||
max_group = 3,
|
||||
biomes = asuna.features.animals.wolf,
|
||||
nodes = {"group:soil"},
|
||||
})
|
||||
|
||||
-- Ambient Spawning
|
||||
|
||||
creatura.register_abm_spawn("animalia:bat", {
|
||||
chance = ambient_spawn_chance,
|
||||
interval = 30,
|
||||
min_light = 0,
|
||||
min_height = -31000,
|
||||
max_height = 1,
|
||||
min_group = 3,
|
||||
max_group = 5,
|
||||
spawn_cap = 6,
|
||||
biomes = asuna.features.animals.bat,
|
||||
nodes = {"group:stone"}
|
||||
})
|
||||
|
||||
creatura.register_abm_spawn("animalia:song_bird", {
|
||||
chance = ambient_spawn_chance,
|
||||
interval = 60,
|
||||
min_light = 0,
|
||||
min_height = 1,
|
||||
max_height = 31000,
|
||||
min_group = 6,
|
||||
max_group = 12,
|
||||
spawn_cap = 6,
|
||||
biomes = asuna.features.animals.song_bird,
|
||||
nodes = {"group:leaves", "animalia:nest_song_bird"},
|
||||
neighbors = {"group:leaves"}
|
||||
})
|
||||
|
||||
creatura.register_on_spawn("animalia:song_bird", function(self, pos)
|
||||
local nests = minetest.find_nodes_in_area_under_air(
|
||||
{x = pos.x - 16, y = pos.y - 16, z = pos.z - 16},
|
||||
{x = pos.x + 16, y = pos.y + 16, z = pos.z + 16},
|
||||
"animalia:nest_song_bird"
|
||||
)
|
||||
if nests[1] then return end
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name == "air" then
|
||||
minetest.set_node(pos, {name = "animalia:nest_song_bird"})
|
||||
else
|
||||
local nodes = minetest.find_nodes_in_area_under_air(
|
||||
{x = pos.x - 3, y = pos.y - 3, z = pos.z - 3},
|
||||
{x = pos.x + 3, y = pos.y + 7, z = pos.z + 3},
|
||||
"group:leaves"
|
||||
)
|
||||
if nodes[1] then
|
||||
pos = nodes[1]
|
||||
minetest.set_node({x = pos.x, y = pos.y + 1, z = pos.z}, {name = "animalia:nest_song_bird"})
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
creatura.register_abm_spawn("animalia:frog", {
|
||||
chance = ambient_spawn_chance * 0.75,
|
||||
interval = 60,
|
||||
min_light = 0,
|
||||
min_height = -1,
|
||||
max_height = 8,
|
||||
min_group = 1,
|
||||
max_group = 2,
|
||||
--neighbors = {"group:water"},
|
||||
nodes = {"group:soil"}
|
||||
})
|
||||
|
||||
creatura.register_on_spawn("animalia:frog", function(self, pos)
|
||||
local biome_data = minetest.get_biome_data(pos)
|
||||
local biome_name = minetest.get_biome_name(biome_data.biome)
|
||||
|
||||
if table_contains(animalia.registered_biome_groups["tropical"].biomes, biome_name) then
|
||||
self:set_mesh(3)
|
||||
elseif table_contains(animalia.registered_biome_groups["temperate"].biomes, biome_name)
|
||||
or table_contains(animalia.registered_biome_groups["boreal"].biomes, biome_name) then
|
||||
self:set_mesh(1)
|
||||
elseif table_contains(animalia.registered_biome_groups["grassland"].biomes, biome_name) then
|
||||
self:set_mesh(2)
|
||||
else
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
local activate = self.activate_func
|
||||
|
||||
activate(self)
|
||||
end)
|
||||
|
||||
creatura.register_abm_spawn("animalia:tropical_fish", {
|
||||
chance = ambient_spawn_chance,
|
||||
min_height = -40,
|
||||
max_height = -2,
|
||||
min_group = 6,
|
||||
max_group = 12,
|
||||
biomes = asuna.features.animals.tropical_fish,
|
||||
nodes = {"group:water","mapgen_water_source"},
|
||||
neighbors = {"group:coral","group:sand"},
|
||||
spawn_in_nodes = true,
|
||||
})
|
||||
|
||||
-- World Gen Spawning
|
||||
|
||||
minetest.register_node("animalia:spawner", {
|
||||
description = "???",
|
||||
drawtype = "airlike",
|
||||
walkable = false,
|
||||
pointable = false,
|
||||
buildable_to = true,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
groups = {oddly_breakable_by_hand = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
minetest.register_decoration({
|
||||
name = "animalia:world_gen_spawning",
|
||||
deco_type = "simple",
|
||||
place_on = {"group:stone", "group:sand", "group:soil"},
|
||||
sidelen = 1,
|
||||
fill_ratio = 0.0001, -- One node per chunk
|
||||
decoration = "animalia:spawner"
|
||||
})
|
||||
|
||||
local function do_on_spawn(pos, obj)
|
||||
local name = obj and obj:get_luaentity().name
|
||||
if not name then return end
|
||||
local spawn_functions = creatura.registered_on_spawns[name] or {}
|
||||
|
||||
if #spawn_functions > 0 then
|
||||
for _, func in ipairs(spawn_functions) do
|
||||
func(obj:get_luaentity(), pos)
|
||||
if not obj:get_yaw() then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
label = "[animalia] World Gen Spawning",
|
||||
nodenames = {"animalia:spawner"},
|
||||
interval = 10, -- TODO: Set this to 1 if world is singleplayer and just started
|
||||
chance = 16,
|
||||
|
||||
action = function(pos, _, active_object_count)
|
||||
minetest.remove_node(pos)
|
||||
|
||||
if active_object_count > 4 then return end
|
||||
|
||||
local spawnable_mobs = {}
|
||||
|
||||
local current_biome = minetest.get_biome_name(minetest.get_biome_data(pos).biome)
|
||||
|
||||
local spawn_definitions = creatura.registered_mob_spawns
|
||||
|
||||
for mob, def in pairs(spawn_definitions) do
|
||||
if mob:match("^animalia:")
|
||||
and def.biomes
|
||||
and table_contains(def.biomes, current_biome) then
|
||||
table.insert(spawnable_mobs, mob)
|
||||
end
|
||||
end
|
||||
|
||||
if #spawnable_mobs > 0 then
|
||||
local mob_to_spawn = spawnable_mobs[math.random(#spawnable_mobs)]
|
||||
local spawn_definition = creatura.registered_mob_spawns[mob_to_spawn]
|
||||
|
||||
local group_size = random(spawn_definition.min_group or 1, spawn_definition.max_group or 1)
|
||||
local obj
|
||||
local mob_positions
|
||||
|
||||
if group_size > 1 then
|
||||
mob_positions = {}
|
||||
local offset
|
||||
local spawn_pos
|
||||
for _ = 1, group_size do
|
||||
offset = group_size * 0.5
|
||||
spawn_pos = creatura.get_ground_level({
|
||||
x = pos.x + random(-offset, offset),
|
||||
y = pos.y,
|
||||
z = pos.z + random(-offset, offset)
|
||||
}, 3)
|
||||
|
||||
if not creatura.is_pos_moveable(spawn_pos, 0.5, 0.5) then
|
||||
table.insert(mob_positions,pos)
|
||||
else
|
||||
table.insert(mob_positions,spawn_pos)
|
||||
end
|
||||
end
|
||||
else
|
||||
mob_positions = { pos }
|
||||
end
|
||||
|
||||
for _,mpos in ipairs(mob_positions) do
|
||||
local node = minetest.get_node(vector.offset(mpos,0,-1,0)).name
|
||||
for _,target in ipairs(spawn_definition.nodes) do
|
||||
if node == target or (target:find("^group:") and minetest.get_item_group(node,target:sub(7)) > 0) then
|
||||
do_on_spawn(mpos, minetest.add_entity(mpos, mob_to_spawn))
|
||||
minetest.log("action","[Animalia] [ABM Spawning] Spawned " .. mob_to_spawn .. " at " .. minetest.pos_to_string(mpos))
|
||||
goto next_mpos
|
||||
end
|
||||
end
|
||||
::next_mpos::
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
22
mods/animalia/api/storage.lua
Normal file
22
mods/animalia/api/storage.lua
Normal file
|
@ -0,0 +1,22 @@
|
|||
local mod_storage = minetest.get_mod_storage()
|
||||
|
||||
local data = {
|
||||
spawn_points = minetest.deserialize(mod_storage:get_string("spawn_points")) or {},
|
||||
libri_font_size = minetest.deserialize(mod_storage:get_string("libri_font_size")) or {},
|
||||
}
|
||||
|
||||
local function save()
|
||||
mod_storage:set_string("spawn_points", minetest.serialize(data.spawn_points))
|
||||
mod_storage:set_string("libri_font_size", minetest.serialize(data.libri_font_size))
|
||||
end
|
||||
|
||||
minetest.register_on_shutdown(save)
|
||||
minetest.register_on_leaveplayer(save)
|
||||
|
||||
local function periodic_save()
|
||||
save()
|
||||
minetest.after(120, periodic_save)
|
||||
end
|
||||
minetest.after(120, periodic_save)
|
||||
|
||||
return data
|
796
mods/animalia/craftitems.lua
Normal file
796
mods/animalia/craftitems.lua
Normal file
|
@ -0,0 +1,796 @@
|
|||
----------------
|
||||
-- Craftitems --
|
||||
----------------
|
||||
|
||||
local random = math.random
|
||||
|
||||
local vec_add, vec_sub = vector.add, vector.subtract
|
||||
|
||||
local color = minetest.colorize
|
||||
|
||||
local function correct_name(str)
|
||||
if str then
|
||||
if str:match(":") then str = str:split(":")[2] end
|
||||
return (string.gsub(" " .. str, "%W%l", string.upper):sub(2):gsub("_", " "))
|
||||
end
|
||||
end
|
||||
|
||||
local function register_egg(name, def)
|
||||
|
||||
minetest.register_entity(def.mob .. "_egg_entity", {
|
||||
hp_max = 1,
|
||||
physical = true,
|
||||
collisionbox = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1},
|
||||
visual = "sprite",
|
||||
visual_size = {x = 0.5, y = 0.5},
|
||||
textures = {def.inventory_image .. ".png"},
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = true,
|
||||
on_step = function(self, _, moveresult)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
if moveresult.collides then
|
||||
for _, collision in ipairs(moveresult.collisions) do
|
||||
if collision.type == "nodes" then
|
||||
minetest.add_particlespawner({
|
||||
amount = 6,
|
||||
time = 0.1,
|
||||
minpos = {x = pos.x - 7/16, y = pos.y - 5/16, z = pos.z - 7/16},
|
||||
maxpos = {x = pos.x + 7/16, y = pos.y - 5/16, z = pos.z + 7/16},
|
||||
minvel = {x = -1, y = 2, z = -1},
|
||||
maxvel = {x = 1, y = 5, z = 1},
|
||||
minacc = {x = 0, y = -9.8, z = 0},
|
||||
maxacc = {x = 0, y = -9.8, z = 0},
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
texture = "animalia_egg_fragment.png"
|
||||
})
|
||||
break
|
||||
elseif collision.type == "object" then
|
||||
collision.object:punch(self.object, 2.0, {full_punch_interval = 0.1, damage_groups = {fleshy = 1}}, nil)
|
||||
break
|
||||
end
|
||||
end
|
||||
if random(3) < 2 then
|
||||
local object = minetest.add_entity(pos, def.mob)
|
||||
local ent = object and object:get_luaentity()
|
||||
if not ent then return end
|
||||
ent.growth_scale = 0.7
|
||||
animalia.initialize_api(ent)
|
||||
animalia.protect_from_despawn(ent)
|
||||
end
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_craftitem(name, {
|
||||
description = def.description,
|
||||
inventory_image = def.inventory_image .. ".png",
|
||||
on_use = function(itemstack, player)
|
||||
local pos = player:get_pos()
|
||||
minetest.sound_play("default_place_node_hard", {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = 5,
|
||||
})
|
||||
local vel = 19
|
||||
local gravity = 9
|
||||
local object = minetest.add_entity({
|
||||
x = pos.x,
|
||||
y = pos.y + 1.5,
|
||||
z = pos.z
|
||||
}, def.mob .. "_egg_entity")
|
||||
local dir = player:get_look_dir()
|
||||
object:set_velocity({
|
||||
x = dir.x * vel,
|
||||
y = dir.y * vel,
|
||||
z = dir.z * vel
|
||||
})
|
||||
object:set_acceleration({
|
||||
x = dir.x * -3,
|
||||
y = -gravity,
|
||||
z = dir.z * -3
|
||||
})
|
||||
itemstack:take_item()
|
||||
return itemstack
|
||||
end,
|
||||
groups = {food_egg = 1, flammable = 2},
|
||||
})
|
||||
|
||||
minetest.register_craftitem(name .. "_fried", {
|
||||
description = "Fried " .. def.description,
|
||||
inventory_image = def.inventory_image .. "_fried.png",
|
||||
on_use = minetest.item_eat(4),
|
||||
groups = {food_egg = 1, flammable = 2},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = name,
|
||||
output = name .. "_fried",
|
||||
})
|
||||
end
|
||||
|
||||
local function mob_storage_use(itemstack, player, pointed)
|
||||
local ent = pointed.ref and pointed.ref:get_luaentity()
|
||||
if ent
|
||||
and (ent.name:match("^animalia:")
|
||||
or ent.name:match("^monstrum:")) then
|
||||
local desc = itemstack:get_short_description()
|
||||
if itemstack:get_count() > 1 then
|
||||
local name = itemstack:get_name()
|
||||
local inv = player:get_inventory()
|
||||
if inv:room_for_item("main", {name = name}) then
|
||||
itemstack:take_item(1)
|
||||
inv:add_item("main", name)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
local plyr_name = player:get_player_name()
|
||||
local meta = itemstack:get_meta()
|
||||
local mob = meta:get_string("mob") or ""
|
||||
if mob == "" then
|
||||
animalia.protect_from_despawn(ent)
|
||||
meta:set_string("mob", ent.name)
|
||||
meta:set_string("staticdata", ent:get_staticdata())
|
||||
local ent_name = correct_name(ent.name)
|
||||
local ent_gender = correct_name(ent.gender)
|
||||
desc = desc .. " \n" .. color("#a9a9a9", ent_name) .. "\n" .. color("#a9a9a9", ent_gender)
|
||||
if ent.trust
|
||||
and ent.trust[plyr_name] then
|
||||
desc = desc .. "\n Trust: " .. color("#a9a9a9", ent.trust[plyr_name])
|
||||
end
|
||||
meta:set_string("description", desc)
|
||||
player:set_wielded_item(itemstack)
|
||||
ent.object:remove()
|
||||
return itemstack
|
||||
else
|
||||
minetest.chat_send_player(plyr_name,
|
||||
"This " .. desc .. " already contains a " .. correct_name(mob))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------
|
||||
-- Drops --
|
||||
-----------
|
||||
|
||||
minetest.register_craftitem("animalia:leather", {
|
||||
description = "Leather",
|
||||
inventory_image = "animalia_leather.png",
|
||||
groups = {flammable = 2, leather = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:feather", {
|
||||
description = "Feather",
|
||||
inventory_image = "animalia_feather.png",
|
||||
groups = {flammable = 2, feather = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:pelt_bear", {
|
||||
description = "Bear Pelt",
|
||||
inventory_image = "animalia_pelt_bear.png",
|
||||
groups = {flammable = 2, pelt = 1},
|
||||
})
|
||||
|
||||
-- Meat --
|
||||
|
||||
minetest.register_craftitem("animalia:beef_raw", {
|
||||
description = "Raw Beef",
|
||||
inventory_image = "animalia_beef_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:beef_cooked", {
|
||||
description = "Steak",
|
||||
inventory_image = "animalia_beef_cooked.png",
|
||||
on_use = minetest.item_eat(8),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:beef_raw",
|
||||
output = "animalia:beef_cooked",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:mutton_raw", {
|
||||
description = "Raw Mutton",
|
||||
inventory_image = "animalia_mutton_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:mutton_cooked", {
|
||||
description = "Cooked Mutton",
|
||||
inventory_image = "animalia_mutton_cooked.png",
|
||||
on_use = minetest.item_eat(6),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:mutton_raw",
|
||||
output = "animalia:mutton_cooked",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:rat_raw", {
|
||||
description = "Raw Rat",
|
||||
inventory_image = "animalia_rat_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:rat_cooked", {
|
||||
description = "Cooked Rat",
|
||||
inventory_image = "animalia_rat_cooked.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:rat_raw",
|
||||
output = "animalia:rat_cooked",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:porkchop_raw", {
|
||||
description = "Raw Porkchop",
|
||||
inventory_image = "animalia_porkchop_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:porkchop_cooked", {
|
||||
description = "Cooked Porkchop",
|
||||
inventory_image = "animalia_porkchop_cooked.png",
|
||||
on_use = minetest.item_eat(7),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:porkchop_raw",
|
||||
output = "animalia:porkchop_cooked",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:poultry_raw", {
|
||||
description = "Raw Poultry",
|
||||
inventory_image = "animalia_poultry_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:poultry_cooked", {
|
||||
description = "Cooked Poultry",
|
||||
inventory_image = "animalia_poultry_cooked.png",
|
||||
on_use = minetest.item_eat(6),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:poultry_raw",
|
||||
output = "animalia:poultry_cooked",
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:venison_raw", {
|
||||
description = "Raw Venison",
|
||||
inventory_image = "animalia_venison_raw.png",
|
||||
on_use = minetest.item_eat(1),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:venison_cooked", {
|
||||
description = "Venison Steak",
|
||||
inventory_image = "animalia_venison_cooked.png",
|
||||
on_use = minetest.item_eat(10),
|
||||
groups = {flammable = 2, meat = 1, food_meat = 1},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
recipe = "animalia:venison_raw",
|
||||
output = "animalia:venison_cooked",
|
||||
})
|
||||
|
||||
register_egg("animalia:chicken_egg", {
|
||||
description = "Chicken Egg",
|
||||
inventory_image = "animalia_egg",
|
||||
mob = "animalia:chicken"
|
||||
})
|
||||
|
||||
register_egg("animalia:turkey_egg", {
|
||||
description = "Turkey Egg",
|
||||
inventory_image = "animalia_egg",
|
||||
mob = "animalia:turkey"
|
||||
})
|
||||
|
||||
register_egg("animalia:song_bird_egg", {
|
||||
description = "Song Bird Egg",
|
||||
inventory_image = "animalia_song_bird_egg",
|
||||
mob = "animalia:bird"
|
||||
})
|
||||
|
||||
----------
|
||||
-- Misc --
|
||||
----------
|
||||
|
||||
minetest.register_craftitem("animalia:bucket_milk", {
|
||||
description = "Bucket of Milk",
|
||||
inventory_image = "animalia_milk_bucket.png",
|
||||
stack_max = 1,
|
||||
on_use = minetest.item_eat(8, "bucket:bucket_empty"),
|
||||
groups = {food_milk = 1, flammable = 3},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:bucket_guano", {
|
||||
description = "Bucket of Guano",
|
||||
inventory_image = "animalia_guano_bucket.png",
|
||||
stack_max = 1,
|
||||
groups = {flammable = 3},
|
||||
on_place = function(itemstack, placer, pointed)
|
||||
local pos = pointed.under
|
||||
local node = minetest.get_node(pos)
|
||||
if node
|
||||
and node.on_rightclick then
|
||||
return node.on_rightclick(pos, node, placer, itemstack)
|
||||
end
|
||||
if minetest.is_protected(pos, placer:get_player_name()) then
|
||||
return
|
||||
end
|
||||
local crops = minetest.find_nodes_in_area_under_air(
|
||||
vec_sub(pos, 5),
|
||||
vec_add(pos, 5),
|
||||
{"group:grass", "group:plant", "group:flora", "group:crop"}
|
||||
) or {}
|
||||
local crops_grown = 0
|
||||
for _, crop in ipairs(crops) do
|
||||
local crop_name = minetest.get_node(crop).name
|
||||
local growth_stage = tonumber(crop_name:sub(-1)) or 1
|
||||
local new_name = crop_name:sub(1, #crop_name - 1) .. (growth_stage + 1)
|
||||
local new_def = minetest.registered_nodes[new_name]
|
||||
if new_def then
|
||||
local p2 = new_def.place_param2 or 1
|
||||
minetest.set_node(crop, {name = new_name, param2 = p2})
|
||||
crops_grown = crops_grown + 1
|
||||
end
|
||||
end
|
||||
if crops_grown < 1 then minetest.set_node(pointed.above, {name = "animalia:guano"}) end
|
||||
local meta = itemstack:get_meta()
|
||||
local og_item = meta:get_string("original_item")
|
||||
if og_item == "" then og_item = "bucket:bucket_empty" end
|
||||
itemstack:replace(ItemStack(og_item))
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_node("animalia:nest_song_bird", {
|
||||
description = "Song Bird Nest",
|
||||
paramtype = "light",
|
||||
drawtype = "mesh",
|
||||
mesh = "animalia_nest.obj",
|
||||
tiles = {"animalia_nest.png"},
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
stack_max = 1,
|
||||
groups = {snappy = 3, flammable = 3, falling_node = 1},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-5 / 16, -0.5, -5 / 16, 5 / 16, -0.31, 5 / 16},
|
||||
},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {-5 / 16, -0.5, -5 / 16, 5 / 16, -0.31, 5 / 16},
|
||||
},
|
||||
drop = {
|
||||
items = {
|
||||
{
|
||||
items = {"animalia:song_bird_egg"},
|
||||
rarity = 2,
|
||||
},
|
||||
{
|
||||
items = {"animalia:song_bird_egg 2"},
|
||||
rarity = 4,
|
||||
},
|
||||
{
|
||||
items = {"default:stick"},
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
-----------
|
||||
-- Tools --
|
||||
-----------
|
||||
|
||||
minetest.register_craftitem("animalia:cat_toy", {
|
||||
description = "Cat Toy",
|
||||
inventory_image = "animalia_cat_toy.png",
|
||||
wield_image = "animalia_cat_toy.png^[transformFYR90",
|
||||
stack_max = 1
|
||||
})
|
||||
|
||||
local nametag = {}
|
||||
|
||||
local function get_rename_formspec(meta)
|
||||
local tag = meta:get_string("name") or ""
|
||||
local form = {
|
||||
"size[8,4]",
|
||||
"field[0.5,1;7.5,0;name;" .. minetest.formspec_escape("Enter name:") .. ";" .. tag .. "]",
|
||||
"button_exit[2.5,3.5;3,1;set_name;" .. minetest.formspec_escape("Set Name") .. "]"
|
||||
}
|
||||
return table.concat(form, "")
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname == "animalia:set_name" and fields.name then
|
||||
local name = player:get_player_name()
|
||||
if not nametag[name] then
|
||||
return
|
||||
end
|
||||
local itemstack = nametag[name]
|
||||
if string.len(fields.name) > 64 then
|
||||
fields.name = string.sub(fields.name, 1, 64)
|
||||
end
|
||||
local meta = itemstack:get_meta()
|
||||
meta:set_string("name", fields.name)
|
||||
meta:set_string("description", fields.name)
|
||||
player:set_wielded_item(itemstack)
|
||||
if fields.quit or fields.key_enter then
|
||||
nametag[name] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function nametag_rightclick(itemstack, player, pointed_thing)
|
||||
if pointed_thing
|
||||
and pointed_thing.type == "object" then
|
||||
return
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
nametag[name] = itemstack
|
||||
local meta = itemstack:get_meta()
|
||||
minetest.show_formspec(name, "animalia:set_name", get_rename_formspec(meta))
|
||||
end
|
||||
|
||||
minetest.register_craftitem("animalia:nametag", {
|
||||
description = "Nametag",
|
||||
inventory_image = "animalia_nametag.png",
|
||||
on_rightclick = nametag_rightclick,
|
||||
on_secondary_use = nametag_rightclick
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:saddle", {
|
||||
description = "Saddle",
|
||||
inventory_image = "animalia_saddle.png",
|
||||
})
|
||||
|
||||
minetest.register_tool("animalia:shears", {
|
||||
description = "Shears",
|
||||
inventory_image = "animalia_shears.png",
|
||||
groups = {flammable = 2}
|
||||
})
|
||||
|
||||
minetest.register_craftitem("animalia:net", {
|
||||
description = "Animal Net",
|
||||
inventory_image = "animalia_net.png",
|
||||
stack_max = 1,
|
||||
on_secondary_use = mob_storage_use,
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local pos = pointed_thing.above
|
||||
if pos then
|
||||
local under = minetest.get_node(pointed_thing.under)
|
||||
local node = minetest.registered_nodes[under.name]
|
||||
if node and node.on_rightclick then
|
||||
return node.on_rightclick(pointed_thing.under, under, placer,
|
||||
itemstack)
|
||||
end
|
||||
if pos and not minetest.is_protected(pos, placer:get_player_name()) then
|
||||
local mob = itemstack:get_meta():get_string("mob")
|
||||
local staticdata = itemstack:get_meta():get_string("staticdata")
|
||||
if mob ~= "" then
|
||||
pos.y = pos.y +
|
||||
math.abs(
|
||||
minetest.registered_entities[mob]
|
||||
.collisionbox[2])
|
||||
minetest.add_entity(pos, mob, staticdata)
|
||||
itemstack:get_meta():set_string("mob", nil)
|
||||
itemstack:get_meta():set_string("staticdata", nil)
|
||||
itemstack:get_meta():set_string("description", "Animal Net")
|
||||
end
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
-----------
|
||||
-- Armor --
|
||||
-----------
|
||||
|
||||
if minetest.get_modpath("3d_armor") then
|
||||
|
||||
if armor
|
||||
and armor.attributes then
|
||||
table.insert(armor.attributes, "heavy_pelt")
|
||||
|
||||
minetest.register_on_punchplayer(function(player, hitter, _, _, _, damage)
|
||||
local name = player:get_player_name()
|
||||
if name
|
||||
and (armor.def[name].heavy_pelt or 0) > 0 then
|
||||
local hit_ip = hitter:is_player()
|
||||
if hit_ip and minetest.is_protected(player:get_pos(), "") then
|
||||
return
|
||||
else
|
||||
local player_pos = player:get_pos()
|
||||
if not player_pos then return end
|
||||
|
||||
local biome_data = minetest.get_biome_data(player_pos)
|
||||
|
||||
if biome_data.heat < 50 then
|
||||
player:set_hp(player:get_hp() - (damage / 1.5))
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
armor:register_armor("animalia:coat_bear_pelt", {
|
||||
description = "Bear Pelt Coat",
|
||||
inventory_image = "animalia_inv_coat_bear_pelt.png",
|
||||
groups = {armor_torso = 1, armor_heal = 0, armor_heavy_pelt = 1, armor_use = 1000},
|
||||
armor_groups = {fleshy = 5}
|
||||
})
|
||||
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:coat_bear_pelt",
|
||||
recipe = {
|
||||
{"animalia:pelt_bear", "", "animalia:pelt_bear"},
|
||||
{"animalia:pelt_bear", "animalia:pelt_bear", "animalia:pelt_bear"},
|
||||
{"animalia:pelt_bear", "animalia:pelt_bear", "animalia:pelt_bear"}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
-----------
|
||||
-- Nodes --
|
||||
-----------
|
||||
|
||||
minetest.register_node("animalia:guano", {
|
||||
description = "Guano",
|
||||
tiles = {"animalia_guano.png"},
|
||||
paramtype = "light",
|
||||
buildable_to = true,
|
||||
floodable = true,
|
||||
walkable = false,
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
|
||||
},
|
||||
},
|
||||
groups = {crumbly = 3, falling_node = 1, not_in_creative_inventory = 1},
|
||||
on_punch = function(pos, _, player)
|
||||
local inv = player:get_inventory()
|
||||
local stack = ItemStack("animalia:bucket_guano")
|
||||
if not inv:room_for_item("main", stack) then return end
|
||||
local item = player:get_wielded_item()
|
||||
local item_name = item:get_name()
|
||||
if item_name:match("bucket_empty") then
|
||||
item:take_item()
|
||||
stack:get_meta():set_string("original_item", item_name)
|
||||
inv:add_item("main", stack)
|
||||
player:set_wielded_item(item)
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_node("animalia:crate", {
|
||||
description = "Animal Crate",
|
||||
tiles = {"animalia_crate.png", "animalia_crate.png", "animalia_crate_side.png"},
|
||||
groups = {choppy = 2},
|
||||
stack_max = 1,
|
||||
on_secondary_use = mob_storage_use,
|
||||
preserve_metadata = function(_, _, oldmeta, drops)
|
||||
for _, stack in pairs(drops) do
|
||||
if stack:get_name() == "animalia:crate" then
|
||||
local meta = stack:get_meta()
|
||||
meta:set_string("mob", oldmeta["mob"])
|
||||
meta:set_string("staticdata", oldmeta["staticdata"])
|
||||
meta:set_string("description", oldmeta["description"])
|
||||
end
|
||||
end
|
||||
end,
|
||||
after_place_node = function(pos, placer, itemstack)
|
||||
local meta = itemstack:get_meta()
|
||||
local mob = meta:get_string("mob")
|
||||
if mob ~= "" then
|
||||
local nmeta = minetest.get_meta(pos)
|
||||
nmeta:set_string("mob", mob)
|
||||
nmeta:set_string("infotext", "Contains a " .. correct_name((mob)))
|
||||
nmeta:set_string("staticdata", meta:get_string("staticdata"))
|
||||
nmeta:set_string("description", meta:get_string("description"))
|
||||
itemstack:take_item()
|
||||
placer:set_wielded_item(itemstack)
|
||||
end
|
||||
end,
|
||||
on_rightclick = function(pos, _, clicker)
|
||||
if minetest.is_protected(pos, clicker:get_player_name()) then
|
||||
return
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local mob = meta:get_string("mob")
|
||||
local staticdata = meta:get_string("staticdata")
|
||||
if mob ~= "" then
|
||||
local above = {
|
||||
x = pos.x,
|
||||
y = pos.y + 1,
|
||||
z = pos.z
|
||||
}
|
||||
if creatura.get_node_def(above).walkable then
|
||||
return
|
||||
end
|
||||
minetest.add_entity(above, mob, staticdata)
|
||||
meta:set_string("mob", nil)
|
||||
meta:set_string("infotext", nil)
|
||||
meta:set_string("staticdata", nil)
|
||||
meta:set_string("description", "Animal Crate")
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
--------------
|
||||
-- Crafting --
|
||||
--------------
|
||||
|
||||
local steel_ingot = "default:steel_ingot"
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
if minetest.registered_items[steel_ingot] then return end
|
||||
for name, _ in pairs(minetest.registered_items) do
|
||||
if name:find("ingot")
|
||||
and (name:find("steel")
|
||||
or name:find("iron")) then
|
||||
steel_ingot = name
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:cat_toy",
|
||||
recipe = {
|
||||
{"", "", "group:thread"},
|
||||
{"", "group:stick", "group:thread"},
|
||||
{"group:stick", "", "group:feather"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:cat_toy",
|
||||
recipe = {
|
||||
{"", "", "farming:string"},
|
||||
{"", "group:stick", "farming:string"},
|
||||
{"group:stick", "", "group:feather"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:lasso",
|
||||
recipe = {
|
||||
{"", "group:thread", "group:thread"},
|
||||
{"", "group:leather", "group:thread"},
|
||||
{"group:thread", "", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:lasso",
|
||||
recipe = {
|
||||
{"", "farming:string", "farming:string"},
|
||||
{"", "group:leather", "farming:string"},
|
||||
{"farming:string", "", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:net",
|
||||
recipe = {
|
||||
{"group:thread", "", "group:thread"},
|
||||
{"group:thread", "", "group:thread"},
|
||||
{"group:stick", "group:thread", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:net",
|
||||
recipe = {
|
||||
{"farming:string", "", "farming:string"},
|
||||
{"farming:string", "", "farming:string"},
|
||||
{"group:stick", "farming:string", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:crate",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"group:wood", "animalia:net", "group:wood"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:saddle",
|
||||
recipe = {
|
||||
{"group:leather", "group:leather", "group:leather"},
|
||||
{"group:leather", steel_ingot, "group:leather"},
|
||||
{"group:thread", "", "group:thread"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:saddle",
|
||||
recipe = {
|
||||
{"group:leather", "group:leather", "group:leather"},
|
||||
{"group:leather", steel_ingot, "group:leather"},
|
||||
{"farming:string", "", "farming:string"}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:shears",
|
||||
recipe = {
|
||||
{"", steel_ingot, ""},
|
||||
{"", "group:leather", steel_ingot}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:libri_animalia",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"animalia:feather", "", ""},
|
||||
{"group:book", "group:color_green", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:libri_animalia",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"animalia:feather", "", ""},
|
||||
{"group:book", "group:unicolor_green", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "animalia:libri_animalia 2",
|
||||
recipe = {
|
||||
{"", "", ""},
|
||||
{"animalia:libri_animalia", "group:book", ""},
|
||||
{"", "", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_on_craft(function(itemstack, _, old_craft_grid)
|
||||
if itemstack:get_name() == "animalia:libri_animalia"
|
||||
and itemstack:get_count() > 1 then
|
||||
for _, old_libri in pairs(old_craft_grid) do
|
||||
if old_libri:get_meta():get_string("chapters") then
|
||||
local chapters = old_libri:get_meta():get_string("chapters")
|
||||
itemstack:get_meta():set_string("chapters", chapters)
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
205
mods/animalia/init.lua
Normal file
205
mods/animalia/init.lua
Normal file
|
@ -0,0 +1,205 @@
|
|||
animalia = {}
|
||||
|
||||
local path = minetest.get_modpath("animalia")
|
||||
|
||||
local storage = dofile(path .. "/api/storage.lua")
|
||||
|
||||
animalia.spawn_points = storage.spawn_points
|
||||
animalia.libri_font_size = storage.libri_font_size
|
||||
|
||||
animalia.pets = {}
|
||||
|
||||
animalia.bones = minetest.registered_items["bonemeal:bone"] and {name = "bonemeal:bone", min = 1, max = 2, chance = 2} or nil
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
animalia.pets[name] = {}
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
animalia.pets[name] = nil
|
||||
end)
|
||||
|
||||
-- Daytime Tracking
|
||||
|
||||
animalia.is_day = true
|
||||
|
||||
local function is_day()
|
||||
local time = (minetest.get_timeofday() or 0) * 24000
|
||||
animalia.is_day = time < 19500 and time > 4500
|
||||
minetest.after(10, is_day)
|
||||
end
|
||||
|
||||
is_day()
|
||||
|
||||
-- Player Effects
|
||||
|
||||
animalia.player_effects = {}
|
||||
|
||||
local function player_effect_step()
|
||||
for player, data in pairs(animalia.player_effects) do
|
||||
if player then
|
||||
local timer = data.timer - 1
|
||||
animalia.player_effects[player].timer = timer
|
||||
local func = data.func
|
||||
func(minetest.get_player_by_name(player))
|
||||
if timer <= 0 then
|
||||
animalia.player_effects[player] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.after(1, player_effect_step)
|
||||
end
|
||||
|
||||
player_effect_step()
|
||||
|
||||
function animalia.set_player_effect(player_name, effect, timer)
|
||||
animalia.player_effects[player_name] = {
|
||||
func = effect,
|
||||
timer = timer or 5
|
||||
}
|
||||
end
|
||||
|
||||
-- Create lists of items for reuse
|
||||
|
||||
animalia.food_wheat = {}
|
||||
animalia.food_seeds = {}
|
||||
animalia.food_crops = {}
|
||||
animalia.food_bear = {}
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
if minetest.get_modpath("farming")
|
||||
and farming.registered_plants then
|
||||
for _, def in pairs(farming.registered_plants) do
|
||||
if def.crop then
|
||||
table.insert(animalia.food_crops, def.crop)
|
||||
end
|
||||
end
|
||||
end
|
||||
for name in pairs(minetest.registered_items) do
|
||||
if (name:match(":wheat")
|
||||
or minetest.get_item_group(name, "food_wheat") > 0)
|
||||
and not name:find("seed") then
|
||||
table.insert(animalia.food_wheat, name)
|
||||
end
|
||||
if name:match(":seed_")
|
||||
or name:match("_seed") then
|
||||
table.insert(animalia.food_seeds, name)
|
||||
end
|
||||
if (minetest.get_item_group(name, "food_berry") > 0
|
||||
and not name:find("seed"))
|
||||
or minetest.get_item_group(name, "food_fish") > 0 then
|
||||
table.insert(animalia.food_bear, name)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Load Files
|
||||
|
||||
local function load_file(filepath, filename)
|
||||
if io.open(filepath .. "/" .. filename, "r") then
|
||||
dofile(filepath .. "/" .. filename)
|
||||
else
|
||||
minetest.log("action", "[Creatura] The file " .. filename .. " could not be loaded.")
|
||||
end
|
||||
end
|
||||
|
||||
dofile(path.."/api/api.lua")
|
||||
dofile(path.."/api/mob_ai.lua")
|
||||
dofile(path.."/api/lasso.lua")
|
||||
dofile(path.."/craftitems.lua")
|
||||
|
||||
animalia.animals = {
|
||||
"animalia:bat",
|
||||
"animalia:song_bird",
|
||||
"animalia:cat",
|
||||
"animalia:chicken",
|
||||
"animalia:cow",
|
||||
"animalia:fox",
|
||||
"animalia:frog",
|
||||
"animalia:grizzly_bear",
|
||||
"animalia:horse",
|
||||
"animalia:opossum",
|
||||
"animalia:owl",
|
||||
"animalia:pig",
|
||||
"animalia:rat",
|
||||
"animalia:reindeer",
|
||||
"animalia:sheep",
|
||||
"animalia:turkey",
|
||||
"animalia:tropical_fish",
|
||||
"animalia:wolf",
|
||||
}
|
||||
|
||||
dofile(path.."/api/api.lua")
|
||||
|
||||
load_file(path .. "/mobs", "bat.lua")
|
||||
load_file(path .. "/mobs", "bear.lua")
|
||||
load_file(path .. "/mobs", "cat.lua")
|
||||
load_file(path .. "/mobs", "chicken.lua")
|
||||
load_file(path .. "/mobs", "cow.lua")
|
||||
load_file(path .. "/mobs", "fox.lua")
|
||||
load_file(path .. "/mobs", "frog.lua")
|
||||
load_file(path .. "/mobs", "horse.lua")
|
||||
load_file(path .. "/mobs", "opossum.lua")
|
||||
load_file(path .. "/mobs", "owl.lua")
|
||||
load_file(path .. "/mobs", "pig.lua")
|
||||
load_file(path .. "/mobs", "rat.lua")
|
||||
load_file(path .. "/mobs", "reindeer.lua")
|
||||
load_file(path .. "/mobs", "sheep.lua")
|
||||
load_file(path .. "/mobs", "song_bird.lua")
|
||||
load_file(path .. "/mobs", "turkey.lua")
|
||||
load_file(path .. "/mobs", "tropical_fish.lua")
|
||||
load_file(path .. "/mobs", "wolf.lua")
|
||||
|
||||
minetest.settings:set_bool("spawn_mobs",asuna.content.menagerie.animals)
|
||||
if minetest.settings:get_bool("spawn_mobs", true) then
|
||||
dofile(path.."/api/spawning.lua")
|
||||
end
|
||||
|
||||
dofile(path.."/api/libri.lua")
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
for name, def in pairs(minetest.registered_entities) do
|
||||
if def.logic
|
||||
or def.brainfunc
|
||||
or def.bh_tree
|
||||
or def._cmi_is_mob then
|
||||
local old_punch = def.on_punch
|
||||
if not old_punch then
|
||||
old_punch = function() end
|
||||
end
|
||||
local on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
old_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local plyr_name = puncher:is_player() and puncher:get_player_name()
|
||||
local pets = (plyr_name and animalia.pets[plyr_name]) or {}
|
||||
for _, obj in ipairs(pets) do
|
||||
local ent = obj and obj:get_luaentity()
|
||||
if ent
|
||||
and ent.assist_owner then
|
||||
ent.owner_target = self
|
||||
end
|
||||
end
|
||||
end
|
||||
def.on_punch = on_punch
|
||||
minetest.register_entity(":" .. name, def)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local convert_mobs_redo = minetest.settings:get_bool("convert_redo_items", false)
|
||||
|
||||
if convert_mobs_redo then
|
||||
minetest.register_alias_force("mobs:leather", "animalia:leather")
|
||||
minetest.register_alias_force("mobs:meat_raw", "animalia:beef_raw")
|
||||
minetest.register_alias_force("mobs:meat", "animalia:beef_cooked")
|
||||
minetest.register_alias_force("mobs:lasso", "animalia:lasso")
|
||||
minetest.register_alias_force("mobs:net", "animalia:net")
|
||||
minetest.register_alias_force("mobs:shears", "animalia:shears")
|
||||
minetest.register_alias_force("mobs:saddles", "animalia:saddles")
|
||||
minetest.register_alias_force("mobs:nametag", "animalia:nametag")
|
||||
end
|
||||
|
||||
minetest.log("action", "[MOD] Animalia [0.6] loaded")
|
7
mods/animalia/libri/animalia_libri_bat.txt
Normal file
7
mods/animalia/libri/animalia_libri_bat.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Bats are a unique flying mammal, found
|
||||
living in large colonies underground. They
|
||||
sleep clinging to the ceiling during day, and
|
||||
leave at night in search of food. While the
|
||||
colony sleeps, Guano accumulates beneath
|
||||
them. This Guano can be picked up with a
|
||||
Bucket and used as fertilizer
|
5
mods/animalia/libri/animalia_libri_bird.txt
Normal file
5
mods/animalia/libri/animalia_libri_bird.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Song Birds are small and brightly colored,
|
||||
often seen moving in flocks swarming
|
||||
through the air near their nests. Each
|
||||
species has a unique call that can be used
|
||||
to identify what Birds are around you.
|
9
mods/animalia/libri/animalia_libri_cat.txt
Normal file
9
mods/animalia/libri/animalia_libri_cat.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
Cats are often found near Human
|
||||
settlements. While typically skittish, their
|
||||
trust can initially be gained by feeding
|
||||
them, and further increased by playing.
|
||||
They don't follow commands well but will
|
||||
do better as their trust grows. However,
|
||||
some habits never die. If you have Cats in
|
||||
your home, never leave down glass vessels
|
||||
unless you want them destroyed.
|
9
mods/animalia/libri/animalia_libri_chicken.txt
Normal file
9
mods/animalia/libri/animalia_libri_chicken.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
Chickens are a flightless bird, most often
|
||||
found in Jungles. They live in tight flocks,
|
||||
wandering along the floor in search of bugs.
|
||||
Males, also called Roosters, are visually
|
||||
distinguised from Females, or hens, by their
|
||||
large tail feathers. Chickens are a popular
|
||||
choice among farmers since they can
|
||||
reliably produce eggs, giving a consistent
|
||||
source of food.
|
5
mods/animalia/libri/animalia_libri_cow.txt
Normal file
5
mods/animalia/libri/animalia_libri_cow.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Cows are large bovines that live in herds.
|
||||
They're a staple of agriculture and are often
|
||||
farmed on large plots of land. They produce
|
||||
Milk and can be slaughtered for Beef, one
|
||||
of the most filling types of meat.
|
7
mods/animalia/libri/animalia_libri_fox.txt
Normal file
7
mods/animalia/libri/animalia_libri_fox.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Foxes wander forests, hunting
|
||||
for their favorite food: Rats.
|
||||
They can be quite helpful in
|
||||
keeping rodent populations
|
||||
down, but also pose a serious
|
||||
threat to Chickens and
|
||||
Turkeys.
|
7
mods/animalia/libri/animalia_libri_frog.txt
Normal file
7
mods/animalia/libri/animalia_libri_frog.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Frogs are a small amphibian found in
|
||||
Swamps. The sound of their croaks often fill
|
||||
the landscape, in addition to the splashes
|
||||
heard as they flee to the water from
|
||||
approaching Humans. Like most
|
||||
amphibians, Frogs breed in water and live in
|
||||
it exclusively as tadpoles.
|
6
mods/animalia/libri/animalia_libri_grizzly_bear.txt
Normal file
6
mods/animalia/libri/animalia_libri_grizzly_bear.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
Large, territorial Omnivores. Bears can be
|
||||
found in colder forests searching for berries.
|
||||
When approached too closely they will lash out
|
||||
with their massive claws. Their pelt can be
|
||||
harvested and crafted into a warm coat that
|
||||
reduces incoming damage in cold weather.
|
13
mods/animalia/libri/animalia_libri_home.txt
Normal file
13
mods/animalia/libri/animalia_libri_home.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
This is a journal of all the
|
||||
Animals you've met in this
|
||||
world. When you find an
|
||||
Animal you wish to log in this
|
||||
Journal, simply right-click it.
|
||||
Doing so will give valuable
|
||||
information on the Animal,
|
||||
including the biomes it
|
||||
inhabits, if and and how it can
|
||||
be tamed, and a general
|
||||
overview of it's behavior.
|
||||
|
||||
Good luck, Explorer!
|
11
mods/animalia/libri/animalia_libri_horse.txt
Normal file
11
mods/animalia/libri/animalia_libri_horse.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
Horses are a large mammal found in open
|
||||
plains. They're commonly used for
|
||||
transportation, as they can run at high
|
||||
speed for vast distances without tiring. To
|
||||
tame one, you have to mount it and keep
|
||||
your view aligned with the Horse's. After
|
||||
taming, the Horse can be saddled and
|
||||
ridden. Not every Horse is created equal,
|
||||
some can jump tremendous heights, and
|
||||
others can run faster. Horses will pass
|
||||
these attributes down to their offspring.
|
5
mods/animalia/libri/animalia_libri_opossum.txt
Normal file
5
mods/animalia/libri/animalia_libri_opossum.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
A unique Marsupial and a key member
|
||||
of it's ecosystem. The Opossum helps
|
||||
keep pests like rodents and insects
|
||||
under control, allowing plantlife and
|
||||
crops to flourish.
|
6
mods/animalia/libri/animalia_libri_owl.txt
Normal file
6
mods/animalia/libri/animalia_libri_owl.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
Owls are a nocturnal bird of prey, most
|
||||
common in forests. Owls play an important
|
||||
role in rodent population control, and are
|
||||
incredibly efficient at it. Their wings are dead
|
||||
silent, allowing them to avoid detection by
|
||||
potential prey.
|
6
mods/animalia/libri/animalia_libri_pig.txt
Normal file
6
mods/animalia/libri/animalia_libri_pig.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
Pigs are medium-sized, forest-dwelling
|
||||
mammals. Males are differentiated from
|
||||
Females by their tusks, which they use to
|
||||
root up food. They're very destructive to
|
||||
crops, so it's best to keep them well
|
||||
contained if you choose to farm them.
|
6
mods/animalia/libri/animalia_libri_rat.txt
Normal file
6
mods/animalia/libri/animalia_libri_rat.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
Rats are common pest on most
|
||||
farms. They slowly eat away at
|
||||
crops and often do so in large
|
||||
numbers. They can also get
|
||||
into any unlocked storage and
|
||||
will eat food from it.
|
5
mods/animalia/libri/animalia_libri_reindeer.txt
Normal file
5
mods/animalia/libri/animalia_libri_reindeer.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Reindeer are among the most common
|
||||
animals found in arctic biomes. They move
|
||||
in large herds, grazing on grass. They're a
|
||||
great alternative to Cattle for those looking
|
||||
to farm meat in cold regions.
|
4
mods/animalia/libri/animalia_libri_sheep.txt
Normal file
4
mods/animalia/libri/animalia_libri_sheep.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
Sheep are a medium mammal that live in
|
||||
medium-large flocks on open prairies. While
|
||||
they can be farmed for mutton, they're more
|
||||
often farmed for their wool.
|
4
mods/animalia/libri/animalia_libri_tropical_fish.txt
Normal file
4
mods/animalia/libri/animalia_libri_tropical_fish.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
Tropical Fish travel in schools among coral
|
||||
reefs. Their brilliant colors are a staple of
|
||||
the ocean, but they don't offer anything as
|
||||
far as food or utility.
|
7
mods/animalia/libri/animalia_libri_turkey.txt
Normal file
7
mods/animalia/libri/animalia_libri_turkey.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Turkeys are a flightless bird found in colder
|
||||
pine forests. As far as utility, they are
|
||||
similar to Chickens, but they drop more
|
||||
meat when killed. Similar to Reindeer,
|
||||
they're a good alternative to other more
|
||||
common livestock that don't live in the
|
||||
same cold regions.
|
5
mods/animalia/libri/animalia_libri_wolf.txt
Normal file
5
mods/animalia/libri/animalia_libri_wolf.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
Wolves are a relatively large canine found
|
||||
in pine forests. They're easy to tame with
|
||||
mutton, and are a very loyal companion.
|
||||
They can be given various orders, and will
|
||||
assist you while fighting.
|
178
mods/animalia/mobs/bat.lua
Normal file
178
mods/animalia/mobs/bat.lua
Normal file
|
@ -0,0 +1,178 @@
|
|||
---------
|
||||
-- Bat --
|
||||
---------
|
||||
|
||||
local vec_dist = vector.distance
|
||||
|
||||
local function get_home_pos(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local nodes = minetest.find_nodes_in_area(
|
||||
vector.subtract(pos, 16),
|
||||
vector.add(pos, 16),
|
||||
{"group:leaves", "group:stone"}
|
||||
)
|
||||
local home_dist
|
||||
local new_home
|
||||
for _, n_pos in ipairs(nodes or {}) do
|
||||
local dist = vec_dist(pos, n_pos)
|
||||
if not home_dist
|
||||
or dist < home_dist then
|
||||
n_pos.y = n_pos.y - 1
|
||||
if creatura.get_node_def(n_pos).name == "air" then
|
||||
home_dist = dist
|
||||
new_home = n_pos
|
||||
end
|
||||
end
|
||||
end
|
||||
if new_home then
|
||||
self.home_position = self:memorize("home_position", new_home)
|
||||
end
|
||||
end
|
||||
|
||||
creatura.register_mob("animalia:bat", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_bat.b3d",
|
||||
textures = {
|
||||
"animalia_bat_1.png",
|
||||
"animalia_bat_2.png",
|
||||
"animalia_bat_3.png",
|
||||
},
|
||||
makes_footstep_sound = false,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 2,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 0,
|
||||
speed = 4,
|
||||
tracking_range = 12,
|
||||
max_boids = 3,
|
||||
despawn_after = 200,
|
||||
max_fall = 0,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_bat",
|
||||
gain = 0.5,
|
||||
distance = 16
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.15,
|
||||
height = 0.3
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 51, y = 69}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
fly = {range = {x = 81, y = 99}, speed = 80, frame_blend = 0.3, loop = true},
|
||||
latch_ceiling = {range = {x = 110, y = 110}, speed = 1, frame_blend = 0, loop = false}
|
||||
},
|
||||
follow = {
|
||||
"butterflies:butterfly_red",
|
||||
"butterflies:butterfly_white",
|
||||
"butterflies:butterfly_violet"
|
||||
},
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
roost_action = animalia.action_latch,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.fly_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.bat_seek_home
|
||||
},
|
||||
|
||||
is_home = function(pos, home_pos)
|
||||
local dist = vec_dist(pos, home_pos)
|
||||
if dist < 4 then
|
||||
local above = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
if creatura.get_node_def(above).walkable
|
||||
or dist < 1 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
self.home_position = self:recall("home_position") or nil
|
||||
local home_pos = self.home_position
|
||||
self.is_landed = self:recall("is_landed") or false
|
||||
self.trust = self:recall("trust") or {}
|
||||
if not home_pos
|
||||
or not creatura.get_node_def(home_pos).walkable then
|
||||
get_home_pos(self)
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.rotate_to_pitch(self)
|
||||
animalia.random_sound(self)
|
||||
if not self.is_landed
|
||||
or not self.touching_ground then
|
||||
self.speed = 4
|
||||
else
|
||||
self.speed = 1
|
||||
end
|
||||
if self:timer(10)
|
||||
and math.random(10) < 2 then
|
||||
local anim = self._anim or ""
|
||||
if anim == "cling" then
|
||||
local colony = creatura.get_nearby_objects(self, self.name)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local center = pos
|
||||
if #colony > 0 then
|
||||
local pos_sum = center
|
||||
local pos_ttl = 1
|
||||
for _, object in ipairs(colony) do
|
||||
local obj_pos = object and object:get_pos()
|
||||
if obj_pos then
|
||||
pos_sum = vector.add(pos_sum, obj_pos)
|
||||
pos_ttl = pos_ttl + 1
|
||||
end
|
||||
end
|
||||
center = vector.divide(pos_sum, pos_ttl)
|
||||
end
|
||||
center = creatura.get_ground_level(center, 8)
|
||||
if center.y < pos.y then
|
||||
local under = {x = center.x, y = center.y - 1, z = center.z}
|
||||
if creatura.get_node_def(under).walkable
|
||||
and not minetest.is_protected(center, "") then
|
||||
minetest.set_node(center, {name = "animalia:guano"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, false) then
|
||||
animalia.add_trust(self, clicker, 1)
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:bat", {
|
||||
col1 = "392517",
|
||||
col2 = "321b0b"
|
||||
})
|
123
mods/animalia/mobs/bear.lua
Normal file
123
mods/animalia/mobs/bear.lua
Normal file
|
@ -0,0 +1,123 @@
|
|||
----------
|
||||
-- Bear --
|
||||
----------
|
||||
|
||||
creatura.register_mob("animalia:grizzly_bear", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_bear.b3d",
|
||||
textures = {
|
||||
"animalia_bear_grizzly.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 20,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 6,
|
||||
speed = 4,
|
||||
tracking_range = 10,
|
||||
despawn_after = 1000,
|
||||
max_fall = 3,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_bear",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_bear_hurt",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_bear_death",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.5,
|
||||
height = 1
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 61, y = 79}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 81, y = 99}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
melee = {range = {x = 101, y = 120}, speed = 30, frame_blend = 0.3, loop = false}
|
||||
},
|
||||
follow = animalia.food_bear,
|
||||
drops = {
|
||||
{name = "animalia:pelt_bear", min = 1, max = 3, chance = 1},
|
||||
animalia.bones,
|
||||
},
|
||||
fancy_collide = false,
|
||||
|
||||
-- Behavior Parameters
|
||||
attacks_players = true,
|
||||
|
||||
-- Animalia Parameters
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.35, z = 0.0},
|
||||
pitch_correction = -45,
|
||||
pivot_h = 0.75,
|
||||
pivot_v = 1
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.basic_seek_food,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.basic_breed
|
||||
},
|
||||
|
||||
on_eat_drop = function(self)
|
||||
local feed_no = (self.feed_no or 0) + 1
|
||||
|
||||
if feed_no >= 5 then
|
||||
feed_no = 0
|
||||
|
||||
if self.breeding then return false end
|
||||
if self.breeding_cooldown <= 0 then
|
||||
self.breeding = true
|
||||
self.breeding_cooldown = 60
|
||||
animalia.particle_spawner(self.stand_pos, "heart.png", "float")
|
||||
end
|
||||
|
||||
self._despawn = self:memorize("_despawn", false)
|
||||
self.despawn_after = self:memorize("despawn_after", false)
|
||||
end
|
||||
self.feed_no = feed_no
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.75, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:grizzly_bear", {
|
||||
col1 = "64361d",
|
||||
col2 = "2c0d03"
|
||||
})
|
227
mods/animalia/mobs/cat.lua
Normal file
227
mods/animalia/mobs/cat.lua
Normal file
|
@ -0,0 +1,227 @@
|
|||
---------
|
||||
-- Cat --
|
||||
---------
|
||||
|
||||
local follow = {
|
||||
"animalia:poultry_raw"
|
||||
}
|
||||
|
||||
if minetest.registered_items["ethereal:fish_raw"] then
|
||||
follow = {
|
||||
"ethereal:fish_raw",
|
||||
"animalia:poultry_raw"
|
||||
}
|
||||
end
|
||||
|
||||
creatura.register_mob("animalia:cat", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_cat.b3d",
|
||||
textures = {
|
||||
"animalia_cat_1.png",
|
||||
"animalia_cat_2.png",
|
||||
"animalia_cat_3.png",
|
||||
"animalia_cat_4.png",
|
||||
"animalia_cat_5.png",
|
||||
"animalia_cat_6.png",
|
||||
"animalia_cat_7.png",
|
||||
"animalia_cat_8.png",
|
||||
"animalia_cat_9.png",
|
||||
"animalia_cat_ash.png",
|
||||
"animalia_cat_birch.png",
|
||||
},
|
||||
use_texture_alpha = false,
|
||||
makes_footstep_sound = false,
|
||||
backface_culling = true,
|
||||
glow = 0,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 10,
|
||||
damage = 1,
|
||||
speed = 3,
|
||||
tracking_range = 16,
|
||||
max_boids = 0,
|
||||
despawn_after = 500,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_cat",
|
||||
gain = 0.25,
|
||||
distance = 8
|
||||
},
|
||||
purr = {
|
||||
name = "animalia_cat_purr",
|
||||
gain = 0.6,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_cat_hurt",
|
||||
gain = 0.25,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_cat_hurt",
|
||||
gain = 0.25,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.2,
|
||||
height = 0.4
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 60}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
sit = {range = {x = 130, y = 139}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = follow,
|
||||
drops = {},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_skittish_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.14, z = 0},
|
||||
pitch_correction = -25,
|
||||
pivot_h = 0.4,
|
||||
pivot_v = 0.4
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.cat_seek_vessel,
|
||||
animalia.mob_ai.cat_stay,
|
||||
animalia.mob_ai.cat_play_with_owner,
|
||||
animalia.mob_ai.cat_follow_owner,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.basic_breed
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
self.interact_sound_cooldown = 0
|
||||
self.trust_cooldown = self:recall("trust_cooldown") or 0
|
||||
self.order = self:recall("order") or "wander"
|
||||
self.owner = self:recall("owner") or nil
|
||||
self.trust = self:recall("trust") or {}
|
||||
if self.owner
|
||||
and minetest.get_player_by_name(self.owner) then
|
||||
if not animalia.pets[self.owner][self.object] then
|
||||
table.insert(animalia.pets[self.owner], self.object)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.75, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
if self:timer(1) then
|
||||
if self.interact_sound_cooldown > 0 then
|
||||
self.interact_sound_cooldown = self.interact_sound_cooldown - 1
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
deactivate_func = function(self)
|
||||
if self.owner then
|
||||
for i, object in ipairs(animalia.pets[self.owner] or {}) do
|
||||
if object == self.object then
|
||||
animalia.pets[self.owner][i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.enemies
|
||||
and self.enemies[1]
|
||||
and self.memorize then
|
||||
self.enemies[1] = nil
|
||||
self.enemies = self:memorize("enemies", self.enemies)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
local item_name = clicker:get_wielded_item():get_name()
|
||||
if item_name == "animalia:net" then return end
|
||||
local trust = self.trust[clicker:get_player_name()] or 0
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
if animalia.feed(self, clicker, true, true) then
|
||||
animalia.add_trust(self, clicker, 1)
|
||||
animalia.particle_spawner(pos, "creatura_particle_green.png", "float")
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
-- Purr to indicate trust level (louder = more trust)
|
||||
if clicker:get_player_control().sneak then
|
||||
if self.interact_sound_cooldown <= 0 then
|
||||
self.sounds["purr"].gain = 0.15 * trust
|
||||
self.interact_sound_cooldown = 3
|
||||
self:play_sound("purr")
|
||||
end
|
||||
end
|
||||
if not self.owner
|
||||
or clicker:get_player_name() ~= self.owner then
|
||||
return
|
||||
end
|
||||
if trust <= 5 then
|
||||
if self.interact_sound_cooldown <= 0 then
|
||||
self.interact_sound_cooldown = 3
|
||||
self:play_sound("random")
|
||||
end
|
||||
return
|
||||
end
|
||||
if clicker:get_player_control().sneak then
|
||||
if self.interact_sound_cooldown <= 0 then
|
||||
self.sounds["purr"].gain = 0.15 * self.trust[self.owner]
|
||||
self.interact_sound_cooldown = 3
|
||||
self:play_sound("purr")
|
||||
end
|
||||
local order = self.order
|
||||
if order == "wander" then
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Cat is following")
|
||||
self.order = "follow"
|
||||
self:initiate_utility("animalia:follow_player", self, clicker, true)
|
||||
self:set_utility_score(0.7)
|
||||
elseif order == "follow" then
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Cat is sitting")
|
||||
self.order = "sit"
|
||||
self:initiate_utility("animalia:stay", self)
|
||||
self:set_utility_score(0.5)
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(), "Cat is wandering")
|
||||
self.order = "wander"
|
||||
self:set_utility_score(0)
|
||||
end
|
||||
self:memorize("order", self.order)
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
self:initiate_utility("animalia:flee_from_player", self, puncher)
|
||||
self:set_utility_score(1)
|
||||
animalia.add_trust(self, puncher, -1)
|
||||
local pos = self.object:get_pos()
|
||||
animalia.particle_spawner(pos, "creatura_particle_red.png", "float")
|
||||
end
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:cat", {
|
||||
col1 = "db9764",
|
||||
col2 = "cf8d5a"
|
||||
})
|
143
mods/animalia/mobs/chicken.lua
Normal file
143
mods/animalia/mobs/chicken.lua
Normal file
|
@ -0,0 +1,143 @@
|
|||
-------------
|
||||
-- Chicken --
|
||||
-------------
|
||||
|
||||
creatura.register_mob("animalia:chicken", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_chicken.b3d",
|
||||
female_textures = {
|
||||
"animalia_chicken_1.png",
|
||||
"animalia_chicken_2.png",
|
||||
"animalia_chicken_3.png"
|
||||
},
|
||||
male_textures = {
|
||||
"animalia_rooster_1.png",
|
||||
"animalia_rooster_2.png",
|
||||
"animalia_rooster_3.png"
|
||||
},
|
||||
child_textures = {"animalia_chicken_child.png"},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 5,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 0,
|
||||
speed = 2,
|
||||
tracking_range = 8,
|
||||
max_boids = 3,
|
||||
despawn_after = 500,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_chicken",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_chicken_hurt",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_chicken_death",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.25,
|
||||
height = 0.5
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 39}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 41, y = 59}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 41, y = 59}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
eat = {range = {x = 61, y = 89}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
fall = {range = {x = 91, y = 99}, speed = 70, frame_blend = 0.3, loop = true}
|
||||
},
|
||||
follow = animalia.food_seeds,
|
||||
drops = {
|
||||
{name = "animalia:poultry_raw", min = 1, max = 3, chance = 1},
|
||||
{name = "animalia:feather", min = 1, max = 3, chance = 2}
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.45, z = 0},
|
||||
pitch_correction = 40,
|
||||
pivot_h = 0.25,
|
||||
pivot_v = 0.55
|
||||
},
|
||||
move_chance = 2,
|
||||
idle_time = 1,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
add_child = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
animalia.particle_spawner(pos, "animalia_egg_fragment.png", "splash", pos, pos)
|
||||
local object = minetest.add_entity(pos, self.name)
|
||||
local ent = object:get_luaentity()
|
||||
ent.growth_scale = 0.7
|
||||
animalia.initialize_api(ent)
|
||||
animalia.protect_from_despawn(ent)
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.75, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
if self.fall_start then
|
||||
self:set_gravity(-4.9)
|
||||
self:animate("fall")
|
||||
end
|
||||
if (self.growth_scale or 1) > 0.8
|
||||
and self.gender == "female"
|
||||
and self:timer(60) then
|
||||
animalia.random_drop_item(self, "animalia:chicken_egg", 10)
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
animalia.set_nametag(self, clicker)
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:chicken", {
|
||||
col1 = "c6c6c6",
|
||||
col2 = "d22222"
|
||||
})
|
169
mods/animalia/mobs/cow.lua
Normal file
169
mods/animalia/mobs/cow.lua
Normal file
|
@ -0,0 +1,169 @@
|
|||
---------
|
||||
-- Cow --
|
||||
---------
|
||||
|
||||
creatura.register_mob("animalia:cow", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_cow.b3d",
|
||||
female_textures = {
|
||||
"animalia_cow_1.png^animalia_cow_udder.png",
|
||||
"animalia_cow_2.png^animalia_cow_udder.png",
|
||||
"animalia_cow_3.png^animalia_cow_udder.png",
|
||||
"animalia_cow_4.png^animalia_cow_udder.png",
|
||||
"animalia_cow_5.png^animalia_cow_udder.png"
|
||||
},
|
||||
male_textures = {
|
||||
"animalia_cow_1.png",
|
||||
"animalia_cow_2.png",
|
||||
"animalia_cow_3.png",
|
||||
"animalia_cow_4.png",
|
||||
"animalia_cow_5.png"
|
||||
},
|
||||
child_textures = {
|
||||
"animalia_cow_1.png",
|
||||
"animalia_cow_2.png",
|
||||
"animalia_cow_3.png",
|
||||
"animalia_cow_4.png",
|
||||
"animalia_cow_5.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 20,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 0,
|
||||
speed = 2,
|
||||
tracking_range = 10,
|
||||
max_boids = 0,
|
||||
despawn_after = 500,
|
||||
max_fall = 3,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_cow",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_cow_hurt",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_cow_death",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.5,
|
||||
height = 1
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 71, y = 89}, speed = 15, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 71, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = animalia.food_wheat,
|
||||
drops = {
|
||||
{name = "animalia:beef_raw", min = 1, max = 3, chance = 1},
|
||||
{name = "animalia:leather", min = 1, max = 3, chance = 2},
|
||||
animalia.bones,
|
||||
},
|
||||
fancy_collide = false,
|
||||
|
||||
-- Behavior Parameters
|
||||
is_grazing_mob = true,
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
consumable_nodes = {
|
||||
["default:dirt_with_grass"] = "default:dirt",
|
||||
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
|
||||
},
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.5, z = 0.0},
|
||||
pitch_correction = -40,
|
||||
pivot_h = 0.75,
|
||||
pivot_v = 1
|
||||
},
|
||||
wander_action = animalia.action_boid_move,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
self.collected = self:recall("collected") or false
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.75, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true)
|
||||
or animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
|
||||
local tool = clicker:get_wielded_item()
|
||||
local name = clicker:get_player_name()
|
||||
|
||||
if tool:get_name() == "bucket:bucket_empty" then
|
||||
|
||||
if self.growth_scale < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
if self.collected then
|
||||
minetest.chat_send_player(name, "This Cow has already been milked.")
|
||||
return
|
||||
end
|
||||
|
||||
local inv = clicker:get_inventory()
|
||||
|
||||
tool:take_item()
|
||||
clicker:set_wielded_item(tool)
|
||||
|
||||
if inv:room_for_item("main", {name = "animalia:bucket_milk"}) then
|
||||
clicker:get_inventory():add_item("main", "animalia:bucket_milk")
|
||||
else
|
||||
local pos = self.object:get_pos()
|
||||
pos.y = pos.y + 0.5
|
||||
minetest.add_item(pos, {name = "animalia:bucket_milk"})
|
||||
end
|
||||
|
||||
self.collected = self:memorize("collected", true)
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:cow", {
|
||||
col1 = "cac3a1",
|
||||
col2 = "464438"
|
||||
})
|
106
mods/animalia/mobs/fox.lua
Normal file
106
mods/animalia/mobs/fox.lua
Normal file
|
@ -0,0 +1,106 @@
|
|||
---------
|
||||
-- Fox --
|
||||
---------
|
||||
|
||||
creatura.register_mob("animalia:fox", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_fox.b3d",
|
||||
textures = {
|
||||
"animalia_fox_1.png"
|
||||
},
|
||||
makes_footstep_sound = false,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 10,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 2,
|
||||
speed = 4,
|
||||
tracking_range = 16,
|
||||
max_boids = 0,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
sound = {},
|
||||
hitbox = {
|
||||
width = 0.35,
|
||||
height = 0.5
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 39}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 41, y = 59}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 41, y = 59}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = {
|
||||
"animalia:rat_raw",
|
||||
"animalia:mutton_raw",
|
||||
"animalia:beef_raw",
|
||||
"animalia:porkchop_raw",
|
||||
"animalia:poultry_raw"
|
||||
},
|
||||
drops = {
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_skittish_mob = true,
|
||||
attack_list = {
|
||||
"animalia:chicken",
|
||||
"animalia:rat"
|
||||
},
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.18, z = 0},
|
||||
pitch_correction = -67,
|
||||
pivot_h = 0.65,
|
||||
pivot_v = 0.65
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.fox_flee,
|
||||
animalia.mob_ai.basic_seek_food,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed
|
||||
},
|
||||
|
||||
on_eat_drop = function(self)
|
||||
animalia.protect_from_despawn(self)
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.5, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, true, true) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:fox", {
|
||||
col1 = "d0602d",
|
||||
col2 = "c9c9c9"
|
||||
})
|
257
mods/animalia/mobs/frog.lua
Normal file
257
mods/animalia/mobs/frog.lua
Normal file
|
@ -0,0 +1,257 @@
|
|||
----------
|
||||
-- Frog --
|
||||
----------
|
||||
|
||||
local random = math.random
|
||||
|
||||
local function poison_effect(object)
|
||||
object:punch(object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 1},
|
||||
})
|
||||
end
|
||||
|
||||
local hitboxes = {
|
||||
{-0.25, 0, -0.25, 0.2, 0.4, 0.25},
|
||||
{-0.4, 0, -0.4, 0.4, 0.5, 0.4},
|
||||
{-0.15, 0, -0.15, 0.15, 0.3, 0.15}
|
||||
}
|
||||
|
||||
local animations = {
|
||||
{
|
||||
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
float = {range = {x = 90, y = 90}, speed = 1, frame_blend = 0.3, loop = true},
|
||||
swim = {range = {x = 90, y = 110}, speed = 50, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 50, y = 80}, speed = 50, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 50, y = 80}, speed = 60, frame_blend = 0.3, loop = true}
|
||||
},
|
||||
{
|
||||
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 50, y = 79}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 50, y = 79}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
warn = {range = {x = 90, y = 129}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
punch = {range = {x = 140, y = 160}, speed = 30, frame_blend = 0.1, loop = false},
|
||||
float = {range = {x = 170, y = 209}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
swim = {range = {x = 220, y = 239}, speed = 20, frame_blend = 0.3, loop = true}
|
||||
},
|
||||
{
|
||||
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 50, y = 69}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 50, y = 69}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
float = {range = {x = 80, y = 119}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
swim = {range = {x = 130, y = 149}, speed = 20, frame_blend = 0.3, loop = true}
|
||||
}
|
||||
}
|
||||
|
||||
local utility_stacks = {
|
||||
{ -- Tree Frog
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_wander,
|
||||
animalia.mob_ai.frog_seek_bug,
|
||||
animalia.mob_ai.frog_breed,
|
||||
animalia.mob_ai.basic_flee,
|
||||
animalia.mob_ai.frog_flop,
|
||||
animalia.mob_ai.frog_seek_water
|
||||
},
|
||||
{ -- Bull Frog
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_wander,
|
||||
animalia.mob_ai.basic_seek_food,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.frog_breed,
|
||||
animalia.mob_ai.frog_flop,
|
||||
animalia.mob_ai.frog_seek_water
|
||||
},
|
||||
{ -- Poison Dart Frog
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_wander,
|
||||
animalia.mob_ai.frog_breed,
|
||||
animalia.mob_ai.basic_flee,
|
||||
animalia.mob_ai.frog_flop,
|
||||
animalia.mob_ai.frog_seek_water
|
||||
}
|
||||
}
|
||||
|
||||
local head_data = {
|
||||
{
|
||||
offset = {x = 0, y = 0.43, z = 0},
|
||||
pitch_correction = -15,
|
||||
pivot_h = 0.3,
|
||||
pivot_v = 0.3
|
||||
},
|
||||
{
|
||||
offset = {x = 0, y = 0.50, z = 0},
|
||||
pitch_correction = -20,
|
||||
pivot_h = 0.3,
|
||||
pivot_v = 0.3
|
||||
},
|
||||
{
|
||||
offset = {x = 0, y = 0.25, z = 0},
|
||||
pitch_correction = -20,
|
||||
pivot_h = 0.3,
|
||||
pivot_v = 0.3
|
||||
}
|
||||
}
|
||||
|
||||
local follow = {
|
||||
{
|
||||
"butterflies:butterfly_white",
|
||||
"butterflies:butterfly_violet",
|
||||
"butterflies:butterfly_red"
|
||||
},
|
||||
{
|
||||
"animalia:rat_raw"
|
||||
},
|
||||
{}
|
||||
}
|
||||
|
||||
creatura.register_mob("animalia:frog", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
meshes = {
|
||||
"animalia_frog.b3d",
|
||||
"animalia_bull_frog.b3d",
|
||||
"animalia_dart_frog.b3d"
|
||||
},
|
||||
child_mesh = "animalia_tadpole.b3d",
|
||||
mesh_textures = {
|
||||
{
|
||||
"animalia_tree_frog.png"
|
||||
},
|
||||
{
|
||||
"animalia_bull_frog.png"
|
||||
},
|
||||
{
|
||||
"animalia_dart_frog_1.png",
|
||||
"animalia_dart_frog_2.png",
|
||||
"animalia_dart_frog_3.png"
|
||||
}
|
||||
},
|
||||
child_textures = {
|
||||
"animalia_tadpole.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 5,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 2,
|
||||
max_breath = 0,
|
||||
speed = 2,
|
||||
tracking_range = 8,
|
||||
max_boids = 0,
|
||||
despawn_after = 300,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
sound = {},
|
||||
hitbox = {
|
||||
width = 0.15,
|
||||
height = 0.3
|
||||
},
|
||||
animations = {},
|
||||
follow = {},
|
||||
drops = {},
|
||||
fancy_collide = false,
|
||||
bouyancy_multiplier = 0,
|
||||
hydrodynamics_multiplier = 0.3,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
head_data = {},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {},
|
||||
|
||||
on_grown = function(self)
|
||||
local mesh_no = self.mesh_no
|
||||
self.animations = animations[mesh_no]
|
||||
self.utility_stack = utility_stacks[mesh_no]
|
||||
self.head_data = head_data[mesh_no]
|
||||
self.object:set_properties({
|
||||
collisionbox = hitboxes[mesh_no]
|
||||
})
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
self.trust = self:recall("trust") or {}
|
||||
|
||||
local mesh_no = self.mesh_no
|
||||
|
||||
-- Set Species Properties
|
||||
if self.growth_scale >= 0.8 then
|
||||
self.animations = animations[mesh_no]
|
||||
self.utility_stack = utility_stacks[mesh_no]
|
||||
self.object:set_properties({
|
||||
collisionbox = hitboxes[mesh_no]
|
||||
})
|
||||
else
|
||||
self.animations = {
|
||||
swim = {range = {x = 1, y = 19}, speed = 20, frame_blend = 0.1, loop = true}
|
||||
}
|
||||
self.utility_stack = utility_stacks[1]
|
||||
end
|
||||
|
||||
self.head_data = head_data[mesh_no]
|
||||
|
||||
if mesh_no == 1 then
|
||||
for i = 1, 15 do
|
||||
local frame = 120 + i
|
||||
local anim = {range = {x = frame, y = frame}, speed = 1, frame_blend = 0.3, loop = false}
|
||||
self.animations["tongue_" .. i] = anim
|
||||
end
|
||||
elseif mesh_no == 2 then
|
||||
self.object:set_armor_groups({fleshy = 50})
|
||||
self.warn_before_attack = true
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.2, 0.2)
|
||||
animalia.do_growth(self, 60)
|
||||
if self:timer(random(5, 15)) then
|
||||
self:play_sound("random")
|
||||
end
|
||||
|
||||
if not self.mesh_vars_set then
|
||||
self.follow = follow[self.mesh_no]
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if self.mesh_no ~= 2 then return end
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
animalia.add_trust(self, clicker, 1)
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
local name = puncher:is_player() and puncher:get_player_name()
|
||||
if name then
|
||||
self.trust[name] = 0
|
||||
self:memorize("trust", self.trust)
|
||||
if self.mesh_no == 3 then
|
||||
animalia.set_player_effect(name, poison_effect, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:frog", {
|
||||
col1 = "67942e",
|
||||
col2 = "294811"
|
||||
})
|
426
mods/animalia/mobs/horse.lua
Normal file
426
mods/animalia/mobs/horse.lua
Normal file
|
@ -0,0 +1,426 @@
|
|||
-----------
|
||||
-- Horse --
|
||||
-----------
|
||||
|
||||
local random = math.random
|
||||
|
||||
-- Horse Inventory
|
||||
|
||||
local form_obj = {}
|
||||
|
||||
local function create_horse_inventory(self)
|
||||
if not self.owner then return end
|
||||
local inv_name = "animalia:horse_" .. self.owner
|
||||
local inv = minetest.create_detached_inventory(inv_name, {
|
||||
allow_move = function(_, _, _, _, _, count)
|
||||
return count
|
||||
end,
|
||||
allow_put = function(_, _, _, stack)
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_take = function(_, _, _, stack)
|
||||
return stack:get_count()
|
||||
end
|
||||
})
|
||||
inv:set_size("main", 12)
|
||||
inv:set_width("main", 4)
|
||||
return inv
|
||||
end
|
||||
|
||||
local function serialize_horse_inventory(self)
|
||||
if not self.owner then return end
|
||||
local inv_name = "animalia:horse_" .. self.owner
|
||||
local inv = minetest.get_inventory({type = "detached", name = inv_name})
|
||||
if not inv then return end
|
||||
local list = inv:get_list("main")
|
||||
local stored = {}
|
||||
for k, item in ipairs(list) do
|
||||
local itemstr = item:to_string()
|
||||
if itemstr ~= "" then
|
||||
stored[k] = itemstr
|
||||
end
|
||||
end
|
||||
self._inventory = self:memorize("_inventory", minetest.serialize(stored))
|
||||
end
|
||||
|
||||
local function get_form(self, player_name)
|
||||
local inv = create_horse_inventory(self)
|
||||
if inv
|
||||
and self._inventory then
|
||||
inv:set_list("main", minetest.deserialize(self._inventory))
|
||||
end
|
||||
|
||||
local frame_range = self.animations["stand"].range
|
||||
local frame_loop = frame_range.x .. "," .. frame_range.y
|
||||
local texture = self:get_props().textures[1]
|
||||
local form = {
|
||||
"formspec_version[3]",
|
||||
"size[10.5,10]",
|
||||
"image[0,0;10.5,5.25;animalia_form_horse_bg.png]",
|
||||
"model[0,0.5;5,3.5;mob_mesh;animalia_horse.b3d;" .. texture .. ";-10,-130;false;false;" .. frame_loop .. ";15]",
|
||||
"list[detached:animalia:horse_" .. player_name .. ";main;5.4,0.5;4,3;]",
|
||||
"list[current_player;main;0.4,4.9;8,4;]",
|
||||
"listring[current_player;main]"
|
||||
}
|
||||
|
||||
return table.concat(form, "")
|
||||
end
|
||||
|
||||
local function close_form(player)
|
||||
local name = player:get_player_name()
|
||||
|
||||
if form_obj[name] then
|
||||
form_obj[name] = nil
|
||||
minetest.remove_detached_inventory("animalia:horse_" .. name)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local name = player:get_player_name()
|
||||
if not form_obj[name] or not form_obj[name]:get_yaw() then
|
||||
return
|
||||
end
|
||||
local obj = form_obj[name]
|
||||
if formname == "animalia:horse_forms" then
|
||||
local ent = obj and obj:get_luaentity()
|
||||
if not ent then return end
|
||||
|
||||
if fields.quit or fields.key_enter then
|
||||
form_obj[name] = nil
|
||||
serialize_horse_inventory(ent)
|
||||
minetest.remove_detached_inventory("animlaia:horse_" .. name)
|
||||
end
|
||||
end
|
||||
|
||||
if formname == "animalia:horse_inv" then
|
||||
local ent = obj and obj:get_luaentity()
|
||||
if not ent then return end
|
||||
|
||||
if fields.quit or fields.key_enter then
|
||||
form_obj[name] = nil
|
||||
serialize_horse_inventory(ent)
|
||||
minetest.remove_detached_inventory("animalia:horse_" .. name)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(close_form)
|
||||
|
||||
-- Pattern
|
||||
|
||||
local patterns = {
|
||||
"animalia_horse_pattern_1.png",
|
||||
"animalia_horse_pattern_2.png",
|
||||
"animalia_horse_pattern_3.png"
|
||||
}
|
||||
|
||||
local avlbl_colors = {
|
||||
[1] = {
|
||||
"animalia_horse_2.png",
|
||||
"animalia_horse_3.png",
|
||||
"animalia_horse_5.png"
|
||||
},
|
||||
[2] = {
|
||||
"animalia_horse_1.png",
|
||||
"animalia_horse_5.png"
|
||||
},
|
||||
[3] = {
|
||||
"animalia_horse_2.png",
|
||||
"animalia_horse_1.png"
|
||||
},
|
||||
[4] = {
|
||||
"animalia_horse_2.png",
|
||||
"animalia_horse_1.png"
|
||||
},
|
||||
[5] = {
|
||||
"animalia_horse_2.png",
|
||||
"animalia_horse_1.png"
|
||||
}
|
||||
}
|
||||
|
||||
local function set_pattern(self)
|
||||
local pattern_no = self:recall("pattern_no")
|
||||
if pattern_no and pattern_no < 1 then return end
|
||||
if not pattern_no then
|
||||
if random(3) < 2 then
|
||||
pattern_no = self:memorize("pattern_no", random(#patterns))
|
||||
else
|
||||
self:memorize("pattern_no", 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
local colors = avlbl_colors[self.texture_no]
|
||||
local color_no = self:recall("color_no") or self:memorize("color_no", random(#colors))
|
||||
if not colors[color_no] then return end
|
||||
local pattern = "(" .. patterns[pattern_no] .. "^[mask:" .. colors[color_no] .. ")"
|
||||
local texture = self.textures[self.texture_no]
|
||||
self.object:set_properties({
|
||||
textures = {texture .. "^" .. pattern}
|
||||
})
|
||||
end
|
||||
|
||||
-- Definition
|
||||
|
||||
creatura.register_mob("animalia:horse", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_horse.b3d",
|
||||
textures = {
|
||||
"animalia_horse_1.png",
|
||||
"animalia_horse_2.png",
|
||||
"animalia_horse_3.png",
|
||||
"animalia_horse_4.png",
|
||||
"animalia_horse_5.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 40,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 8,
|
||||
speed = 10,
|
||||
tracking_range = 16,
|
||||
max_boids = 7,
|
||||
despawn_after = 1000,
|
||||
max_fall = 4,
|
||||
stepheight = 1.2,
|
||||
sounds = {
|
||||
alter_child_pitch = true,
|
||||
random = {
|
||||
name = "animalia_horse_idle",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_horse_hurt",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_horse_death",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.65,
|
||||
height = 1.95
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
punch_aoe = {range = {x = 170, y = 205}, speed = 30, frame_blend = 0.2, loop = false},
|
||||
rear = {range = {x = 130, y = 160}, speed = 20, frame_blend = 0.1, loop = false},
|
||||
eat = {range = {x = 210, y = 240}, speed = 30, frame_blend = 0.3, loop = false}
|
||||
},
|
||||
follow = animalia.food_wheat,
|
||||
drops = {
|
||||
{name = "animalia:leather", min = 1, max = 4, chance = 2},
|
||||
animalia.bones,
|
||||
},
|
||||
fancy_collide = false,
|
||||
|
||||
-- Behavior Parameters
|
||||
is_grazing_mob = true,
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
consumable_nodes = {
|
||||
["default:dirt_with_grass"] = "default:dirt",
|
||||
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
|
||||
},
|
||||
head_data = {
|
||||
bone = "Neck.CTRL",
|
||||
offset = {x = 0, y = 1.4, z = 0.0},
|
||||
pitch_correction = 15,
|
||||
pivot_h = 1,
|
||||
pivot_v = 1.75
|
||||
},
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee,
|
||||
{
|
||||
utility = "animalia:horse_tame",
|
||||
get_score = function(self)
|
||||
local rider = not self.owner and self.rider
|
||||
if rider
|
||||
and rider:get_pos() then
|
||||
return 0.7, {self}
|
||||
end
|
||||
return 0
|
||||
end
|
||||
},
|
||||
{
|
||||
utility = "animalia:horse_ride",
|
||||
get_score = function(self)
|
||||
if not self.owner then return 0 end
|
||||
local owner = self.owner and minetest.get_player_by_name(self.owner)
|
||||
local rider = owner == self.rider and self.rider
|
||||
if rider
|
||||
and rider:get_pos() then
|
||||
return 0.8, {self, rider}
|
||||
end
|
||||
return 0
|
||||
end
|
||||
}
|
||||
},
|
||||
|
||||
-- Functions
|
||||
set_saddle = function(self, saddle)
|
||||
if saddle then
|
||||
self.saddled = self:memorize("saddled", true)
|
||||
local texture = self.object:get_properties().textures[1]
|
||||
self.object:set_properties({
|
||||
textures = {texture .. "^animalia_horse_saddle.png"}
|
||||
})
|
||||
self.drops = {
|
||||
{name = "animalia:leather", chance = 2, min = 1, max = 4},
|
||||
{name = "animalia:saddle", chance = 1, min = 1, max = 1}
|
||||
}
|
||||
else
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
self.saddled = self:memorize("saddled", false)
|
||||
set_pattern(self)
|
||||
self.drops = {
|
||||
{name = "animalia:leather", chance = 2, min = 1, max = 4}
|
||||
}
|
||||
minetest.add_item(pos, "animalia:saddle")
|
||||
end
|
||||
end,
|
||||
|
||||
add_child = function(self, mate)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local obj = minetest.add_entity(pos, self.name)
|
||||
local ent = obj and obj:get_luaentity()
|
||||
if not ent then return end
|
||||
ent.growth_scale = 0.7
|
||||
local tex_no = self.texture_no
|
||||
local mate_ent = mate and mate:get_luaentity()
|
||||
if mate_ent
|
||||
or not mate_ent.speed
|
||||
or not mate_ent.jump_power
|
||||
or not mate_ent.max_health then
|
||||
return
|
||||
end
|
||||
if random(2) < 2 then
|
||||
tex_no = mate_ent.texture_no
|
||||
end
|
||||
ent:memorize("texture_no", tex_no)
|
||||
ent:memorize("speed", random(mate_ent.speed, self.speed))
|
||||
ent:memorize("jump_power", random(mate_ent.jump_power, self.jump_power))
|
||||
ent:memorize("max_health", random(mate_ent.max_health, self.max_health))
|
||||
ent.speed = ent:recall("speed")
|
||||
ent.jump_power = ent:recall("jump_power")
|
||||
ent.max_health = ent:recall("max_health")
|
||||
animalia.initialize_api(ent)
|
||||
animalia.protect_from_despawn(ent)
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
set_pattern(self)
|
||||
|
||||
self.owner = self:recall("owner") or nil
|
||||
|
||||
if self.owner then
|
||||
self._inventory = self:recall("_inventory")
|
||||
end
|
||||
|
||||
self.rider = nil
|
||||
self.saddled = self:recall("saddled") or false
|
||||
self.max_health = self:recall("max_health") or random(30, 45)
|
||||
self.speed = self:recall("speed") or random(5, 10)
|
||||
self.jump_power = self:recall("jump_power") or random(2, 5)
|
||||
self:memorize("max_health", self.max_health)
|
||||
self:memorize("speed", self.speed)
|
||||
self:memorize("jump_power", self.jump_power)
|
||||
if self.saddled then
|
||||
self:set_saddle(true)
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self.rider then
|
||||
animalia.mount(self, self.rider)
|
||||
end
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
|
||||
local owner = self.owner
|
||||
local name = clicker and clicker:get_player_name()
|
||||
if owner and name ~= owner then return end
|
||||
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
|
||||
local wielded_name = clicker:get_wielded_item():get_name()
|
||||
|
||||
if wielded_name == "animalia:saddle" then
|
||||
self:set_saddle(true)
|
||||
return
|
||||
end
|
||||
|
||||
if clicker:get_player_control().sneak
|
||||
and owner then
|
||||
minetest.show_formspec(name, "animalia:horse_forms", get_form(self, name))
|
||||
form_obj[name] = self.object
|
||||
elseif wielded_name == "" then
|
||||
animalia.mount(self, clicker, {rot = {x = -65, y = 180, z = 0}, pos = {x = 0, y = 0.75, z = 0.6}})
|
||||
if self.saddled then
|
||||
self:initiate_utility("animalia:mount", self, clicker)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(self, puncher, ...)
|
||||
if self.rider and puncher == self.rider then return end
|
||||
local name = puncher:is_player() and puncher:get_player_name()
|
||||
if name
|
||||
and name == self.owner
|
||||
and puncher:get_player_control().sneak then
|
||||
self:set_saddle(false)
|
||||
return
|
||||
end
|
||||
animalia.punch(self, puncher, ...)
|
||||
end,
|
||||
|
||||
on_detach_child = function(self, child)
|
||||
if child
|
||||
and self.rider == child then
|
||||
self.rider = nil
|
||||
child:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
|
||||
child:set_properties({visual_size = {x = 1, y = 1}})
|
||||
animalia.animate_player(child, "stand", 30)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:horse", {
|
||||
col1 = "ebdfd8",
|
||||
col2 = "653818"
|
||||
})
|
105
mods/animalia/mobs/opossum.lua
Normal file
105
mods/animalia/mobs/opossum.lua
Normal file
|
@ -0,0 +1,105 @@
|
|||
-------------
|
||||
-- Opossum --
|
||||
-------------
|
||||
|
||||
creatura.register_mob("animalia:opossum", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_opossum.b3d",
|
||||
textures = {
|
||||
"animalia_opossum.png"
|
||||
},
|
||||
makes_footstep_sound = false,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 5,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 2,
|
||||
speed = 4,
|
||||
tracking_range = 16,
|
||||
max_boids = 0,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
max_fall = 8,
|
||||
sound = {},
|
||||
hitbox = {
|
||||
width = 0.25,
|
||||
height = 0.4
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
feint = {range = {x = 130, y = 130}, speed = 45, frame_blend = 0.3, loop = false},
|
||||
clean_crop = {range = {x = 171, y = 200}, speed = 15, frame_blend = 0.2, loop = false}
|
||||
},
|
||||
follow = {
|
||||
"animalia:song_bird_egg",
|
||||
"animalia:rat_raw",
|
||||
"animalia:mutton_raw",
|
||||
"animalia:beef_raw",
|
||||
"animalia:porkchop_raw",
|
||||
"animalia:poultry_raw"
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_skittish_mob = true,
|
||||
attack_list = {"animalia:rat"},
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.18, z = 0},
|
||||
pitch_correction = -67,
|
||||
pivot_h = 0.65,
|
||||
pivot_v = 0.65
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.opossum_feint,
|
||||
animalia.mob_ai.opossum_seek_crop,
|
||||
animalia.mob_ai.basic_seek_food,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed
|
||||
},
|
||||
|
||||
on_eat_drop = function(self)
|
||||
animalia.protect_from_despawn(self)
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.5, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, true, true) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:opossum", {
|
||||
col1 = "75665f",
|
||||
col2 = "ccbfb8"
|
||||
})
|
169
mods/animalia/mobs/owl.lua
Normal file
169
mods/animalia/mobs/owl.lua
Normal file
|
@ -0,0 +1,169 @@
|
|||
---------
|
||||
-- Owl --
|
||||
---------
|
||||
|
||||
local abs = math.abs
|
||||
|
||||
local vec_dist = vector.distance
|
||||
|
||||
local function get_home_pos(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local leaves = minetest.find_nodes_in_area_under_air(
|
||||
vector.subtract(pos, 16),
|
||||
vector.add(pos, 16),
|
||||
"group:leaves"
|
||||
)
|
||||
local home_dist
|
||||
local new_home
|
||||
for _, leaf_pos in ipairs(leaves or {}) do
|
||||
local dist = vec_dist(pos, leaf_pos)
|
||||
if not home_dist
|
||||
or dist < home_dist then
|
||||
home_dist = dist
|
||||
new_home = leaf_pos
|
||||
end
|
||||
end
|
||||
if new_home then
|
||||
new_home.y = new_home.y + 1
|
||||
self.home_position = self:memorize("home_position", new_home)
|
||||
end
|
||||
end
|
||||
|
||||
creatura.register_mob("animalia:owl", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_owl.b3d",
|
||||
textures = {
|
||||
"animalia_owl.png"
|
||||
},
|
||||
makes_footstep_sound = false,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 10,
|
||||
damage = 2,
|
||||
speed = 4,
|
||||
tracking_range = 16,
|
||||
max_boids = 0,
|
||||
despawn_after = 500,
|
||||
max_fall = 0,
|
||||
sound = {}, -- TODO
|
||||
hitbox = {
|
||||
width = 0.15,
|
||||
height = 0.3
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 60}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
fly = {range = {x = 71, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
glide = {range = {x = 101, y = 119}, speed = 20, frame_blend = 0.2, loop = true},
|
||||
fly_punch = {range = {x = 131, y = 149}, speed = 20, frame_blend = 0.1, loop = false},
|
||||
eat = {range = {x = 161, y = 179}, speed = 20, frame_blend = 0.1, loop = false}
|
||||
},
|
||||
follow = {"animalia:rat_raw"},
|
||||
drops = {
|
||||
{name = "animalia:feather", min = 1, max = 2, chance = 1}
|
||||
},
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true, -- TODO
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
roost_action = animalia.action_roost,
|
||||
|
||||
-- Functions
|
||||
on_eat_drop = function(self)
|
||||
animalia.protect_from_despawn(self)
|
||||
get_home_pos(self)
|
||||
end,
|
||||
|
||||
is_home = function(pos, home_pos)
|
||||
if abs(pos.x - home_pos.x) < 0.5
|
||||
and abs(pos.z - home_pos.z) < 0.5 then
|
||||
if abs(pos.y - home_pos.y) < 0.75 then
|
||||
return true
|
||||
else
|
||||
local under = {x = home_pos.x, y = home_pos.y, z = home_pos.z}
|
||||
local name = minetest.get_node(under).name
|
||||
if minetest.get_node_group(name, "leaves") > 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end,
|
||||
|
||||
wander_action = creatura.action_move,
|
||||
|
||||
utility_stack = {
|
||||
animalia.mob_ai.fly_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.bat_seek_home,
|
||||
animalia.mob_ai.fly_seek_food,
|
||||
animalia.mob_ai.eagle_attack
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
self._tp2home = self:recall("_tp2home") or nil
|
||||
self.home_position = self:recall("home_position") or nil
|
||||
local home_pos = self.home_position
|
||||
if self._tp2home
|
||||
and home_pos then
|
||||
self.object:set_pos(home_pos)
|
||||
end
|
||||
self.is_landed = self:recall("is_landed") or false
|
||||
if not home_pos
|
||||
or creatura.get_node_def(home_pos).walkable then
|
||||
get_home_pos(self)
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.rotate_to_pitch(self)
|
||||
if not self.is_landed
|
||||
or not self.touching_ground then
|
||||
self.speed = 5
|
||||
else
|
||||
self.speed = 1
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
deactivate_func = function(self)
|
||||
if self:get_utility()
|
||||
and self:get_utility() == "animalia:fly_to_roost" then
|
||||
local pos = self.home_position
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if node
|
||||
and not creatura.get_node_def(node.name).walkable
|
||||
and minetest.get_natural_light(pos) > 0 then
|
||||
self:memorize("_tp2home", true)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, false) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:owl", {
|
||||
col1 = "412918",
|
||||
col2 = "735b46"
|
||||
})
|
120
mods/animalia/mobs/pig.lua
Normal file
120
mods/animalia/mobs/pig.lua
Normal file
|
@ -0,0 +1,120 @@
|
|||
---------
|
||||
-- Pig --
|
||||
---------
|
||||
|
||||
creatura.register_mob("animalia:pig", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_pig.b3d",
|
||||
female_textures = {
|
||||
"animalia_pig_1.png",
|
||||
"animalia_pig_2.png",
|
||||
"animalia_pig_3.png"
|
||||
},
|
||||
male_textures = {
|
||||
"animalia_pig_1.png^animalia_pig_tusks.png",
|
||||
"animalia_pig_2.png^animalia_pig_tusks.png",
|
||||
"animalia_pig_3.png^animalia_pig_tusks.png"
|
||||
},
|
||||
child_textures = {
|
||||
"animalia_pig_1.png",
|
||||
"animalia_pig_2.png",
|
||||
"animalia_pig_3.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 20,
|
||||
damage = 2,
|
||||
speed = 3,
|
||||
tracking_range = 12,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_pig",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_pig_hurt",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_pig_death",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.35,
|
||||
height = 0.7
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 60}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = animalia.food_crops,
|
||||
drops = {
|
||||
{name = "animalia:porkchop_raw", min = 1, max = 3, chance = 1},
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
birth_count = 2,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.7, z = 0},
|
||||
pitch_correction = 0,
|
||||
pivot_h = 0.5,
|
||||
pivot_v = 0.3
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.basic_seek_crop,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.head_tracking(self)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:pig", {
|
||||
col1 = "e0b1a7",
|
||||
col2 = "cc9485"
|
||||
})
|
82
mods/animalia/mobs/rat.lua
Normal file
82
mods/animalia/mobs/rat.lua
Normal file
|
@ -0,0 +1,82 @@
|
|||
----------
|
||||
-- Mice --
|
||||
----------
|
||||
|
||||
creatura.register_mob("animalia:rat", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_rat.b3d",
|
||||
textures = {
|
||||
"animalia_rat_1.png",
|
||||
"animalia_rat_2.png",
|
||||
"animalia_rat_3.png"
|
||||
},
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 5,
|
||||
damage = 0,
|
||||
speed = 1,
|
||||
tracking_range = 8,
|
||||
despawn_after = 200,
|
||||
stepheight = 1.1,
|
||||
--sound = {},
|
||||
hitbox = {
|
||||
width = 0.15,
|
||||
height = 0.3
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 39}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 51, y = 69}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 81, y = 99}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
eat = {range = {x = 111, y = 119}, speed = 20, frame_blend = 0.1, loop = false}
|
||||
},
|
||||
drops = {
|
||||
{name = "animalia:rat_raw", min = 1, max = 1, chance = 1}
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_skittish_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.basic_seek_crop,
|
||||
animalia.mob_ai.rat_seek_chest,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:rat", {
|
||||
col1 = "605a55",
|
||||
col2 = "ff936f"
|
||||
})
|
119
mods/animalia/mobs/reindeer.lua
Normal file
119
mods/animalia/mobs/reindeer.lua
Normal file
|
@ -0,0 +1,119 @@
|
|||
--------------
|
||||
-- Reindeer --
|
||||
--------------
|
||||
|
||||
creatura.register_mob("animalia:reindeer", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_reindeer.b3d",
|
||||
textures = {"animalia_reindeer.png"},
|
||||
child_textures = {"animalia_reindeer_calf.png"},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 15,
|
||||
damage = 0,
|
||||
speed = 3,
|
||||
tracking_range = 12,
|
||||
max_boids = 4,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_reindeer",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_reindeer_hurt",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_reindeer_death",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.45,
|
||||
height = 0.9
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
eat = {range = {x = 130, y = 150}, speed = 20, frame_blend = 0.3, loop = false}
|
||||
},
|
||||
follow = animalia.food_wheat,
|
||||
drops = {
|
||||
{name = "animalia:venison_raw", min = 1, max = 3, chance = 1},
|
||||
{name = "animalia:leather", min = 1, max = 3, chance = 2},
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_grazing_mob = true,
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
consumable_nodes = {
|
||||
{
|
||||
name = "default:dirt_with_grass",
|
||||
replacement = "default:dirt"
|
||||
},
|
||||
{
|
||||
name = "default:dry_dirt_with_dry_grass",
|
||||
replacement = "default:dry_dirt"
|
||||
}
|
||||
},
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.55, z = 0},
|
||||
pitch_correction = -45,
|
||||
pivot_h = 1,
|
||||
pivot_v = 1
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:reindeer", {
|
||||
col1 = "413022",
|
||||
col2 = "d5c0a3"
|
||||
})
|
199
mods/animalia/mobs/sheep.lua
Normal file
199
mods/animalia/mobs/sheep.lua
Normal file
|
@ -0,0 +1,199 @@
|
|||
-----------
|
||||
-- Sheep --
|
||||
-----------
|
||||
|
||||
local random = math.random
|
||||
|
||||
local palette = {
|
||||
black = {"Black", "#000000b0"},
|
||||
blue = {"Blue", "#015dbb70"},
|
||||
brown = {"Brown", "#663300a0"},
|
||||
cyan = {"Cyan", "#01ffd870"},
|
||||
dark_green = {"Dark Green", "#005b0770"},
|
||||
dark_grey = {"Dark Grey", "#303030b0"},
|
||||
green = {"Green", "#61ff0170"},
|
||||
grey = {"Grey", "#5b5b5bb0"},
|
||||
magenta = {"Magenta", "#ff05bb70"},
|
||||
orange = {"Orange", "#ff840170"},
|
||||
pink = {"Pink", "#ff65b570"},
|
||||
red = {"Red", "#ff0000a0"},
|
||||
violet = {"Violet", "#2000c970"},
|
||||
white = {"White", "#ababab00"},
|
||||
yellow = {"Yellow", "#e3ff0070"},
|
||||
}
|
||||
|
||||
creatura.register_mob("animalia:sheep", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_sheep.b3d",
|
||||
textures = {
|
||||
"animalia_sheep.png^animalia_sheep_wool.png"
|
||||
},
|
||||
child_textures = {
|
||||
"animalia_sheep.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 15,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 0,
|
||||
speed = 3,
|
||||
tracking_range = 12,
|
||||
max_boids = 4,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_sheep",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_sheep_hurt",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_sheep_death",
|
||||
gain = 1.0,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.4,
|
||||
height = 0.8
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
eat = {range = {x = 130, y = 150}, speed = 20, frame_blend = 0.3, loop = false}
|
||||
},
|
||||
follow = animalia.food_wheat,
|
||||
drops = {
|
||||
{name = "animalia:mutton_raw", min = 1, max = 3, chance = 1},
|
||||
minetest.get_modpath("wool") and {name = "wool:white", min = 1, max = 3, chance = 2} or nil,
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_grazing_mob = true,
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
consumable_nodes = {
|
||||
["default:dirt_with_grass"] = "default:dirt",
|
||||
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
|
||||
},
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.41, z = 0},
|
||||
pitch_correction = -45,
|
||||
pivot_h = 0.75,
|
||||
pivot_v = 0.85
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
|
||||
self.collected = self:recall("collected") or false
|
||||
self.dye_color = self:recall("dye_color") or "white"
|
||||
if self.collected then
|
||||
self.object:set_properties({
|
||||
textures = {"animalia_sheep.png"},
|
||||
})
|
||||
elseif self.dye_color ~= "white" then
|
||||
self.object:set_properties({
|
||||
textures = {"animalia_sheep.png^(animalia_sheep_wool.png^[multiply:" .. palette[self.dye_color][2] .. ")"},
|
||||
})
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
if self.collected
|
||||
or self.growth_scale < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local tool = clicker:get_wielded_item()
|
||||
local tool_name = tool:get_name()
|
||||
local creative = minetest.is_creative_enabled(clicker:get_player_name())
|
||||
|
||||
if tool_name == "animalia:shears" then
|
||||
if not minetest.get_modpath("wool") then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.add_item(
|
||||
self.object:get_pos(),
|
||||
ItemStack("wool:" .. self.dye_color .. " " .. random(1, 3))
|
||||
)
|
||||
|
||||
self.collected = self:memorize("collected", true)
|
||||
self.dye_color = self:memorize("dye_color", "white")
|
||||
|
||||
self.object:set_properties({
|
||||
textures = {"animalia_sheep.png"},
|
||||
})
|
||||
|
||||
if not creative then
|
||||
tool:add_wear(650)
|
||||
clicker:set_wielded_item(tool)
|
||||
end
|
||||
end
|
||||
|
||||
if tool_name:match("^dye:") then
|
||||
local dye_color = tool_name:split(":")[2]
|
||||
if palette[dye_color] then
|
||||
self.dye_color = self:memorize("dye_color", dye_color)
|
||||
self.drops = {
|
||||
{name = "animalia:mutton_raw", chance = 1, min = 1, max = 4},
|
||||
{name = "wool:" .. dye_color, chance = 2, min = 1, max = 2},
|
||||
}
|
||||
self.object:set_properties({
|
||||
textures = {"animalia_sheep.png^(animalia_sheep_wool.png^[multiply:" .. palette[dye_color][2] .. ")"},
|
||||
})
|
||||
if not creative then
|
||||
tool:take_item()
|
||||
clicker:set_wielded_item(tool)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:sheep", {
|
||||
col1 = "f4e6cf",
|
||||
col2 = "e1ca9b"
|
||||
})
|
138
mods/animalia/mobs/song_bird.lua
Normal file
138
mods/animalia/mobs/song_bird.lua
Normal file
|
@ -0,0 +1,138 @@
|
|||
---------------
|
||||
-- Song Bird --
|
||||
---------------
|
||||
|
||||
local random = math.random
|
||||
|
||||
creatura.register_mob("animalia:song_bird", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_bird.b3d",
|
||||
textures = {
|
||||
"animalia_cardinal.png",
|
||||
"animalia_bluebird.png",
|
||||
"animalia_goldfinch.png"
|
||||
},
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 2,
|
||||
speed = 4,
|
||||
tracking_range = 8,
|
||||
max_boids = 6,
|
||||
boid_seperation = 0.3,
|
||||
despawn_after = 200,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
cardinal = {
|
||||
name = "animalia_cardinal",
|
||||
gain = 0.5,
|
||||
distance = 63
|
||||
},
|
||||
eastern_blue = {
|
||||
name = "animalia_bluebird",
|
||||
gain = 0.5,
|
||||
distance = 63
|
||||
},
|
||||
goldfinch = {
|
||||
name = "animalia_goldfinch",
|
||||
gain = 0.5,
|
||||
distance = 63
|
||||
},
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.2,
|
||||
height = 0.4
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 100}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 110, y = 130}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
fly = {range = {x = 140, y = 160}, speed = 40, frame_blend = 0.3, loop = true}
|
||||
},
|
||||
--follow = {},
|
||||
drops = {
|
||||
{name = "animalia:feather", min = 1, max = 1, chance = 2}
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
uses_boids = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
wander_action = animalia.action_boid_move,
|
||||
--roost_action = animalia.action_roost,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.fly_landing_wander,
|
||||
animalia.mob_ai.fly_seek_land
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
if animalia.despawn_inactive_mob(self) then return end
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
self.is_landed = (random(2) < 2 and true) or false
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
--animalia.update_lasso_effects(self)
|
||||
animalia.rotate_to_pitch(self)
|
||||
if self:timer(random(6, 12)) then
|
||||
if animalia.is_day then
|
||||
if self.texture_no == 1 then
|
||||
self:play_sound("cardinal")
|
||||
elseif self.texture_no == 2 then
|
||||
self:play_sound("eastern_blue")
|
||||
else
|
||||
self:play_sound("goldfinch")
|
||||
end
|
||||
end
|
||||
end
|
||||
if not self.is_landed
|
||||
or not self.touching_ground then
|
||||
self.speed = 4
|
||||
else
|
||||
self.speed = 3
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = animalia.death_func,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
--[[if animalia.feed(self, clicker, false, false) then
|
||||
return
|
||||
end]]
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:song_bird", {
|
||||
col1 = "ae2f2f",
|
||||
col2 = "f3ac1c"
|
||||
})
|
||||
|
||||
minetest.register_entity("animalia:bird", {
|
||||
static_save = false,
|
||||
on_activate = function(self)
|
||||
self.object:remove()
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
label = "animalia:nest_cleanup",
|
||||
nodenames = "animalia:nest_song_bird",
|
||||
interval = 900,
|
||||
action = function(pos)
|
||||
minetest.remove_node(pos)
|
||||
end
|
||||
})
|
91
mods/animalia/mobs/tropical_fish.lua
Normal file
91
mods/animalia/mobs/tropical_fish.lua
Normal file
|
@ -0,0 +1,91 @@
|
|||
----------
|
||||
-- Fish --
|
||||
----------
|
||||
|
||||
creatura.register_mob("animalia:tropical_fish", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
meshes = {
|
||||
"animalia_clownfish.b3d",
|
||||
"animalia_angelfish.b3d"
|
||||
},
|
||||
mesh_textures = {
|
||||
{
|
||||
"animalia_clownfish.png",
|
||||
"animalia_blue_tang.png"
|
||||
},
|
||||
{
|
||||
"animalia_angelfish.png"
|
||||
}
|
||||
},
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 5,
|
||||
armor_groups = {fleshy = 150},
|
||||
damage = 0,
|
||||
max_breath = 0,
|
||||
speed = 2,
|
||||
tracking_range = 6,
|
||||
max_boids = 6,
|
||||
boid_seperation = 0.3,
|
||||
despawn_after = 200,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
hitbox = {
|
||||
width = 0.15,
|
||||
height = 0.3
|
||||
},
|
||||
animations = {
|
||||
swim = {range = {x = 1, y = 20}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
flop = {range = {x = 30, y = 40}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
liquid_submergence = 1,
|
||||
liquid_drag = 0,
|
||||
|
||||
-- Animalia Behaviors
|
||||
is_aquatic_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
flee_puncher = false,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = false,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.swim_wander
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:tropical_fish", {
|
||||
col1 = "e28821",
|
||||
col2 = "f6e5d2"
|
||||
})
|
||||
|
||||
animalia.alias_mob("animalia:clownfish", "animalia:tropical_fish")
|
||||
animalia.alias_mob("animalia:blue_tang", "animalia:tropical_fish")
|
||||
animalia.alias_mob("animalia:angelfish", "animalia:tropical_fish")
|
133
mods/animalia/mobs/turkey.lua
Normal file
133
mods/animalia/mobs/turkey.lua
Normal file
|
@ -0,0 +1,133 @@
|
|||
------------
|
||||
-- Turkey --
|
||||
------------
|
||||
|
||||
creatura.register_mob("animalia:turkey", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_turkey.b3d",
|
||||
female_textures = {"animalia_turkey_hen.png"},
|
||||
male_textures = {"animalia_turkey_tom.png"},
|
||||
child_textures = {"animalia_turkey_chick.png"},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 8,
|
||||
armor_groups = {fleshy = 100},
|
||||
damage = 0,
|
||||
speed = 2,
|
||||
tracking_range = 8,
|
||||
max_boids = 3,
|
||||
despawn_after = 500,
|
||||
max_fall = 0,
|
||||
stepheight = 1.1,
|
||||
sounds = {
|
||||
random = {
|
||||
name = "animalia_turkey",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
hurt = {
|
||||
name = "animalia_turkey_hurt",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
},
|
||||
death = {
|
||||
name = "animalia_turkey_death",
|
||||
gain = 0.5,
|
||||
distance = 8
|
||||
}
|
||||
},
|
||||
hitbox = {
|
||||
width = 0.3,
|
||||
height = 0.6
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 0, y = 0}, speed = 1, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 10, y = 30}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 40, y = 60}, speed = 45, frame_blend = 0.3, loop = true},
|
||||
fall = {range = {x = 70, y = 90}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = animalia.food_seeds,
|
||||
drops = {
|
||||
{name = "animalia:poultry_raw", min = 1, max = 4, chance = 1},
|
||||
{name = "animalia:feather", min = 1, max = 3, chance = 2},
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Animalia Props
|
||||
group_wander = true,
|
||||
flee_puncher = true,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.15, z = 0},
|
||||
pitch_correction = 45,
|
||||
pivot_h = 0.45,
|
||||
pivot_v = 0.65
|
||||
},
|
||||
move_chance = 2,
|
||||
idle_time = 1,
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_breed,
|
||||
animalia.mob_ai.basic_flee
|
||||
},
|
||||
|
||||
add_child = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
animalia.particle_spawner(pos, "animalia_egg_fragment.png", "splash", pos, pos)
|
||||
local object = minetest.add_entity(pos, self.name)
|
||||
local ent = object:get_luaentity()
|
||||
ent.growth_scale = 0.7
|
||||
animalia.initialize_api(ent)
|
||||
animalia.protect_from_despawn(ent)
|
||||
end,
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self, 0.75, 0.75)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
animalia.random_sound(self)
|
||||
if self.fall_start then
|
||||
self:set_gravity(-4.9)
|
||||
self:animate("fall")
|
||||
end
|
||||
if (self.growth_scale or 1) > 0.8
|
||||
and self.gender == "female"
|
||||
and self:timer(60) then
|
||||
animalia.random_drop_item(self, "animalia:turkey_egg", 10)
|
||||
end
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if animalia.feed(self, clicker, false, true) then
|
||||
return
|
||||
end
|
||||
animalia.set_nametag(self, clicker)
|
||||
end,
|
||||
|
||||
on_punch = animalia.punch
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:turkey", {
|
||||
col1 = "352b22",
|
||||
col2 = "2f2721"
|
||||
})
|
198
mods/animalia/mobs/wolf.lua
Normal file
198
mods/animalia/mobs/wolf.lua
Normal file
|
@ -0,0 +1,198 @@
|
|||
----------
|
||||
-- Wolf --
|
||||
----------
|
||||
|
||||
|
||||
|
||||
local follow = {
|
||||
"animalia:mutton_raw",
|
||||
"animalia:beef_raw",
|
||||
"animalia:porkchop_raw",
|
||||
"animalia:poultry_raw"
|
||||
}
|
||||
|
||||
if minetest.registered_items["bonemeal:bone"] then
|
||||
follow = {
|
||||
"bonemeal:bone",
|
||||
"animalia:beef_raw",
|
||||
"animalia:porkchop_raw",
|
||||
"animalia:mutton_raw",
|
||||
"animalia:poultry_raw"
|
||||
}
|
||||
end
|
||||
|
||||
local function is_value_in_table(tbl, val)
|
||||
for _, v in pairs(tbl) do
|
||||
if v == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
creatura.register_mob("animalia:wolf", {
|
||||
-- Engine Props
|
||||
visual_size = {x = 10, y = 10},
|
||||
mesh = "animalia_wolf.b3d",
|
||||
textures = {
|
||||
"animalia_wolf_1.png",
|
||||
"animalia_wolf_2.png",
|
||||
"animalia_wolf_3.png",
|
||||
"animalia_wolf_4.png"
|
||||
},
|
||||
makes_footstep_sound = true,
|
||||
|
||||
-- Creatura Props
|
||||
max_health = 20,
|
||||
damage = 4,
|
||||
speed = 4,
|
||||
tracking_range = 24,
|
||||
despawn_after = 500,
|
||||
stepheight = 1.1,
|
||||
sound = {},
|
||||
hitbox = {
|
||||
width = 0.35,
|
||||
height = 0.7
|
||||
},
|
||||
animations = {
|
||||
stand = {range = {x = 1, y = 60}, speed = 20, frame_blend = 0.3, loop = true},
|
||||
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
|
||||
run = {range = {x = 100, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
|
||||
sit = {range = {x = 130, y = 139}, speed = 10, frame_blend = 0.3, loop = true},
|
||||
},
|
||||
follow = follow,
|
||||
drops = {
|
||||
animalia.bones,
|
||||
},
|
||||
|
||||
-- Behavior Parameters
|
||||
is_skittish_mob = true,
|
||||
is_herding_mob = true,
|
||||
|
||||
-- Animalia Props
|
||||
assist_owner = true,
|
||||
flee_puncher = false,
|
||||
catch_with_net = true,
|
||||
catch_with_lasso = true,
|
||||
consumable_nodes = {},
|
||||
head_data = {
|
||||
offset = {x = 0, y = 0.22, z = 0},
|
||||
pitch_correction = -35,
|
||||
pivot_h = 0.45,
|
||||
pivot_v = 0.45
|
||||
},
|
||||
|
||||
-- Functions
|
||||
utility_stack = {
|
||||
animalia.mob_ai.basic_wander,
|
||||
animalia.mob_ai.swim_seek_land,
|
||||
animalia.mob_ai.tamed_stay,
|
||||
animalia.mob_ai.tamed_follow_owner,
|
||||
animalia.mob_ai.basic_attack,
|
||||
animalia.mob_ai.basic_breed
|
||||
},
|
||||
|
||||
activate_func = function(self)
|
||||
animalia.initialize_api(self)
|
||||
animalia.initialize_lasso(self)
|
||||
self.order = self:recall("order") or "wander"
|
||||
self.owner = self:recall("owner") or nil
|
||||
self.enemies = self:recall("enemies") or {}
|
||||
if self.owner
|
||||
and minetest.get_player_by_name(self.owner) then
|
||||
if not is_value_in_table(animalia.pets[self.owner], self.object) then
|
||||
table.insert(animalia.pets[self.owner], self.object)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
step_func = function(self)
|
||||
animalia.step_timers(self)
|
||||
animalia.head_tracking(self)
|
||||
animalia.do_growth(self, 60)
|
||||
animalia.update_lasso_effects(self)
|
||||
end,
|
||||
|
||||
death_func = function(self)
|
||||
if self:get_utility() ~= "animalia:die" then
|
||||
self:initiate_utility("animalia:die", self)
|
||||
end
|
||||
end,
|
||||
|
||||
deactivate_func = function(self)
|
||||
if self.owner then
|
||||
for i, object in ipairs(animalia.pets[self.owner] or {}) do
|
||||
if object == self.object then
|
||||
animalia.pets[self.owner][i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.enemies
|
||||
and self.enemies[1]
|
||||
and self.memorize then
|
||||
self.enemies[1] = nil
|
||||
self.enemies = self:memorize("enemies", self.enemies)
|
||||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(self, clicker)
|
||||
if not clicker:is_player() then return end
|
||||
local name = clicker:get_player_name()
|
||||
local passive = true
|
||||
if is_value_in_table(self.enemies, name) then passive = false end
|
||||
if animalia.feed(self, clicker, passive, passive) then
|
||||
return
|
||||
end
|
||||
if animalia.set_nametag(self, clicker) then
|
||||
return
|
||||
end
|
||||
if self.owner
|
||||
and name == self.owner
|
||||
and clicker:get_player_control().sneak then
|
||||
local order = self.order
|
||||
if order == "wander" then
|
||||
minetest.chat_send_player(name, "Wolf is following")
|
||||
self.order = "follow"
|
||||
self:initiate_utility("animalia:follow_player", self, clicker, true)
|
||||
self:set_utility_score(0.7)
|
||||
elseif order == "follow" then
|
||||
minetest.chat_send_player(name, "Wolf is sitting")
|
||||
self.order = "sit"
|
||||
self:initiate_utility("animalia:stay", self)
|
||||
self:set_utility_score(0.5)
|
||||
else
|
||||
minetest.chat_send_player(name, "Wolf is wandering")
|
||||
self.order = "wander"
|
||||
self:set_utility_score(0)
|
||||
end
|
||||
self:memorize("order", self.order)
|
||||
end
|
||||
end,
|
||||
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
|
||||
local name = puncher:is_player() and puncher:get_player_name()
|
||||
if name then
|
||||
if self.owner
|
||||
and name == self.owner then
|
||||
return
|
||||
elseif not is_value_in_table(self.enemies, name) then
|
||||
table.insert(self.enemies, name)
|
||||
if #self.enemies > 15 then
|
||||
table.remove(self.enemies, 1)
|
||||
end
|
||||
self.enemies = self:memorize("enemies", self.enemies)
|
||||
else
|
||||
table.remove(self.enemies, 1)
|
||||
table.insert(self.enemies, name)
|
||||
self.enemies = self:memorize("enemies", self.enemies)
|
||||
end
|
||||
end
|
||||
self._target = puncher
|
||||
end,
|
||||
})
|
||||
|
||||
creatura.register_spawn_item("animalia:wolf", {
|
||||
col1 = "a19678",
|
||||
col2 = "231b13"
|
||||
})
|
6
mods/animalia/mod.conf
Normal file
6
mods/animalia/mod.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
name = animalia
|
||||
depends = creatura
|
||||
optional_depends = default, mcl_player, farming, 3d_armor, bonemeal
|
||||
description = Adds unique and consistantly designed Animals
|
||||
title = Animalia
|
||||
author = ElCeejo
|
BIN
mods/animalia/models/animala_horse.b3d
Normal file
BIN
mods/animalia/models/animala_horse.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_angelfish.b3d
Normal file
BIN
mods/animalia/models/animalia_angelfish.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_bat.b3d
Normal file
BIN
mods/animalia/models/animalia_bat.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_bear.b3d
Normal file
BIN
mods/animalia/models/animalia_bear.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_bird.b3d
Normal file
BIN
mods/animalia/models/animalia_bird.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_bull_frog.b3d
Normal file
BIN
mods/animalia/models/animalia_bull_frog.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_cat.b3d
Normal file
BIN
mods/animalia/models/animalia_cat.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_chicken.b3d
Normal file
BIN
mods/animalia/models/animalia_chicken.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_clownfish.b3d
Normal file
BIN
mods/animalia/models/animalia_clownfish.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_cow.b3d
Normal file
BIN
mods/animalia/models/animalia_cow.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_dart_frog.b3d
Normal file
BIN
mods/animalia/models/animalia_dart_frog.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_fox.b3d
Normal file
BIN
mods/animalia/models/animalia_fox.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_frog.b3d
Normal file
BIN
mods/animalia/models/animalia_frog.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_horse.b3d
Normal file
BIN
mods/animalia/models/animalia_horse.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_lasso.b3d
Normal file
BIN
mods/animalia/models/animalia_lasso.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_lasso_entity.b3d
Normal file
BIN
mods/animalia/models/animalia_lasso_entity.b3d
Normal file
Binary file not shown.
49
mods/animalia/models/animalia_nest.obj
Normal file
49
mods/animalia/models/animalia_nest.obj
Normal file
|
@ -0,0 +1,49 @@
|
|||
# Made in Blockbench 4.1.5
|
||||
mtllib animalia_nest.mtl
|
||||
|
||||
o cube
|
||||
v 0.3125 -0.3125 0.3125
|
||||
v 0.3125 -0.3125 -0.3125
|
||||
v 0.3125 -0.5 0.3125
|
||||
v 0.3125 -0.5 -0.3125
|
||||
v -0.3125 -0.3125 -0.3125
|
||||
v -0.3125 -0.3125 0.3125
|
||||
v -0.3125 -0.5 -0.3125
|
||||
v -0.3125 -0.5 0.3125
|
||||
vt 0.16666666666666666 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 0.45833333333333337
|
||||
vt 0.16666666666666666 0.45833333333333337
|
||||
vt 0.16666666666666666 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 0.45833333333333337
|
||||
vt 0.16666666666666666 0.45833333333333337
|
||||
vt 0.16666666666666666 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 0.45833333333333337
|
||||
vt 0.16666666666666666 0.45833333333333337
|
||||
vt 0.16666666666666666 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 0.45833333333333337
|
||||
vt 0.16666666666666666 0.45833333333333337
|
||||
vt 1 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 1
|
||||
vt 1 1
|
||||
vt 1 0.5833333333333333
|
||||
vt 0.5833333333333334 0.5833333333333333
|
||||
vt 0.5833333333333334 0.16666666666666663
|
||||
vt 1 0.16666666666666663
|
||||
vn 0 0 -1
|
||||
vn 1 0 0
|
||||
vn 0 0 1
|
||||
vn -1 0 0
|
||||
vn 0 1 0
|
||||
vn 0 -1 0
|
||||
usemtl m_1
|
||||
f 4/4/1 7/3/1 5/2/1 2/1/1
|
||||
f 3/8/2 4/7/2 2/6/2 1/5/2
|
||||
f 8/12/3 3/11/3 1/10/3 6/9/3
|
||||
f 7/16/4 8/15/4 6/14/4 5/13/4
|
||||
f 6/20/5 1/19/5 2/18/5 5/17/5
|
||||
f 7/24/6 4/23/6 3/22/6 8/21/6
|
BIN
mods/animalia/models/animalia_opossum.b3d
Normal file
BIN
mods/animalia/models/animalia_opossum.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_owl.b3d
Normal file
BIN
mods/animalia/models/animalia_owl.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_pig.b3d
Normal file
BIN
mods/animalia/models/animalia_pig.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_rat.b3d
Normal file
BIN
mods/animalia/models/animalia_rat.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_reindeer.b3d
Normal file
BIN
mods/animalia/models/animalia_reindeer.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_sheep.b3d
Normal file
BIN
mods/animalia/models/animalia_sheep.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_tadpole.b3d
Normal file
BIN
mods/animalia/models/animalia_tadpole.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_turkey.b3d
Normal file
BIN
mods/animalia/models/animalia_turkey.b3d
Normal file
Binary file not shown.
BIN
mods/animalia/models/animalia_wolf.b3d
Normal file
BIN
mods/animalia/models/animalia_wolf.b3d
Normal file
Binary file not shown.
29
mods/animalia/settingtypes.txt
Normal file
29
mods/animalia/settingtypes.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
# How many chunks can generate before adding another to spawn queue
|
||||
chunk_spawn_add_int (Chunk Spawning Addition Interval) float 6
|
||||
|
||||
# How often (in seconds) the spawn queue is executed and cleared
|
||||
chunk_spawn_queue_int (Chunk Spawning Queue Execution Interval) float 16
|
||||
|
||||
# If true, mobs will spawn in the wild
|
||||
spawn_mobs (Spawn Mobs) bool true
|
||||
|
||||
# If true, items from mobs_redo and mobs_animal will be converted to Animalia items
|
||||
convert_redo_items(Convert Mobs Redo Items) bool false
|
||||
|
||||
# If true, Guano will accumulate under resting bats
|
||||
guano_accumulation (Guano Accumulation) bool true
|
||||
|
||||
# If true, Guano can be used as fertilizer
|
||||
guano_fertilization (Guano Fertilization) bool true
|
||||
|
||||
# Chance for Common Mobs to spawn (1 in x nodes will spawn a mob every minute)
|
||||
animalia_common_chance (Common Mob Spawn Chance) int 40000 20000 60000
|
||||
|
||||
# Chance for Ambient Mobs to spawn (1 in x nodes will spawn a mob every minute)
|
||||
animalia_ambient_chance (Ambient Mob Spawn Chance) int 15000 5000 25000
|
||||
|
||||
# Chance for Pest Mobs to spawn (1 in x nodes will spawn a mob every minute)
|
||||
animalia_pest_chance (Pest Mob Spawn Chance) int 5000 100 15000
|
||||
|
||||
# Chance for Common Mobs to spawn (1 in x nodes will spawn a mob every minute)
|
||||
animalia_predator_chance (Predator Mob Spawn Chance) int 40000 20000 50000
|
BIN
mods/animalia/sounds/animalia_bat_1.ogg
Normal file
BIN
mods/animalia/sounds/animalia_bat_1.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/animalia_bat_2.ogg
Normal file
BIN
mods/animalia/sounds/animalia_bat_2.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/animalia_horse_whistle.ogg
Normal file
BIN
mods/animalia/sounds/animalia_horse_whistle.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.1.ogg
Normal file
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.1.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.2.ogg
Normal file
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.2.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.3.ogg
Normal file
BIN
mods/animalia/sounds/bluebird/animalia_bluebird.3.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.1.ogg
Normal file
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.1.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.2.ogg
Normal file
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.2.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.3.ogg
Normal file
BIN
mods/animalia/sounds/cardinal/animalia_cardinal.3.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cat/animalia_cat_hurt.ogg
Normal file
BIN
mods/animalia/sounds/cat/animalia_cat_hurt.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cat/animalia_cat_idle.ogg
Normal file
BIN
mods/animalia/sounds/cat/animalia_cat_idle.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cat/animalia_cat_purr.ogg
Normal file
BIN
mods/animalia/sounds/cat/animalia_cat_purr.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/chicken/animalia_chicken.ogg
Normal file
BIN
mods/animalia/sounds/chicken/animalia_chicken.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/chicken/animalia_chicken_death.ogg
Normal file
BIN
mods/animalia/sounds/chicken/animalia_chicken_death.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/chicken/animalia_chicken_hurt.ogg
Normal file
BIN
mods/animalia/sounds/chicken/animalia_chicken_hurt.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cow/animalia_cow.ogg
Normal file
BIN
mods/animalia/sounds/cow/animalia_cow.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cow/animalia_cow_death.ogg
Normal file
BIN
mods/animalia/sounds/cow/animalia_cow_death.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/cow/animalia_cow_hurt.ogg
Normal file
BIN
mods/animalia/sounds/cow/animalia_cow_hurt.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/frog/animalia_frog_1.ogg
Normal file
BIN
mods/animalia/sounds/frog/animalia_frog_1.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/frog/animalia_frog_2.ogg
Normal file
BIN
mods/animalia/sounds/frog/animalia_frog_2.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/frog/animalia_frog_3.ogg
Normal file
BIN
mods/animalia/sounds/frog/animalia_frog_3.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.1.ogg
Normal file
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.1.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.2.ogg
Normal file
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.2.ogg
Normal file
Binary file not shown.
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.3.ogg
Normal file
BIN
mods/animalia/sounds/goldfinch/animalia_goldfinch.3.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue