Initial Commit

This commit is contained in:
ElCeejo 2020-11-11 23:16:50 -08:00 committed by GitHub
parent 7dca0f6da4
commit 0b7971e2c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1592 additions and 0 deletions

527
api/api.lua Normal file
View file

@ -0,0 +1,527 @@
-------------
---- API ----
-------------
-- Ver 0.1 --
local random = math.random
local pi = math.pi
local abs = math.abs
local ceil = math.ceil
local vec_dist = vector.distance
local abr = minetest.get_mapgen_setting('active_block_range')
local function hitbox(self) return self.object:get_properties().collisionbox end
local walkable_nodes = {}
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_nodes) do
if name ~= "air" and name ~= "ignore" then
if minetest.registered_nodes[name].walkable then
table.insert(walkable_nodes,name)
end
end
end
end)
function better_fauna.particle_spawner(pos, texture, type, min_pos, max_pos)
type = type or "float"
min_pos = min_pos or {
x = pos.x - 2,
y = pos.y - 2,
z = pos.z - 2,
}
max_pos = max_pos or {
x = pos.x + 2,
y = pos.y + 2,
z = pos.z + 2,
}
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 = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
minsize = 2,
maxsize = 4,
collisiondetection = true,
texture = texture,
})
end
end
---------------------------
-- Mob Control Functions --
---------------------------
local function can_fit(pos, width)
local pos1 = vector.new(pos.x - width, pos.y, pos.z - width)
local pos2 = vector.new(pos.x + width, pos.y, pos.z + width)
for x = pos1.x, pos2.x do
for y = pos1.y, pos2.y do
for z = pos1.z, pos2.z do
local p2 = vector.new(x, y, z)
local node = minetest.get_node(p2)
if minetest.registered_nodes[node.name].walkable then
local p3 = vector.new(p2.x, p2.y + 1, p2.z)
local node2 = minetest.get_node(p3)
if minetest.registered_nodes[node2.name].walkable then
return false
end
end
end
end
end
return true
end
local function move_from_wall(pos, width)
local pos1 = vector.new(pos.x - width, pos.y, pos.z - width)
local pos2 = vector.new(pos.x + width, pos.y, pos.z + width)
for x = pos1.x, pos2.x do
for y = pos1.y, pos2.y do
for z = pos1.z, pos2.z do
local p2 = vector.new(x, y, z)
if can_fit(p2, width) then
return p2
end
end
end
end
return pos
end
function better_fauna.find_path(pos, tpos, width)
local endpos = tpos
if not minetest.registered_nodes[minetest.get_node(
vector.new(endpos.x, endpos.y - 1, endpos.z))
.name].walkable then
local min = vector.subtract(endpos, 1)
local max = vector.add(endpos, 1)
local index_table = minetest.find_nodes_in_area_under_air( min, max, better_fauna.walkable_nodes)
for _, i_pos in pairs(index_table) do
if minetest.registered_nodes[minetest.get_node(i_pos)
.name].walkable then
endpos = vector.new(i_pos.x, i_pos.y + 1, i_pos.z)
break
end
end
end
local path = minetest.find_path(pos, endpos, 32, 1, 1, "A*_noprefetch")
if not path
or #path < 2 then return end
table.remove(path, 1)
table.remove(path, #path)
for i = #path, 1, -1 do
if not path then return end
if not can_fit(path[i], width + 1) then
local clear = move_from_wall(path[i], width + 1)
if clear and can_fit(clear, width) then
path[i] = clear
end
end
if #path > 3 then
local pos1 = path[i - 2]
local pos2 = path[i]
-- Handle Diagonals
if pos1
and pos2
and pos1.x ~= pos2.x
and pos1.z ~= pos2.z then
if minetest.line_of_sight(pos1, pos2) then
local pos3 = vector.divide(vector.add(pos1, pos2), 2)
if can_fit(pos, width) then
table.remove(path, i - 1)
end
end
end
-- Reduce Straight Lines
if pos1
and pos2
and pos1.x == pos2.x
and pos1.z ~= pos2.z
and pos1.y == pos2.y then
if minetest.line_of_sight(pos1, pos2) then
local pos3 = vector.divide(vector.add(pos1, pos2), 2)
if can_fit(pos, width) then
table.remove(path, i - 1)
end
end
elseif pos1
and pos2
and pos1.x ~= pos2.x
and pos1.z == pos2.z
and pos1.y == pos2.y then
if minetest.line_of_sight(pos1, pos2) then
local pos3 = vector.divide(vector.add(pos1, pos2), 2)
if can_fit(pos, width) then
table.remove(path, i - 1)
end
end
end
end
end
if #path > 2 then
if vector.distance(pos, path[2]) <= width + 1 then
for i = 3, #path do
path[i - 1] = path[i]
end
end
end
return path
end
function better_fauna.path_to_next_waypoint(self, tpos, speed_factor)
speed_factor = speed_factor or 1
local pos = self.object:get_pos()
local path_data = better_fauna.find_path(pos, tpos, 1)
if not path_data
or #path_data < 2 then
return true
end
local pos2 = path_data[2]
if pos2 then
local yaw = self.object:get_yaw()
local tyaw = minetest.dir_to_yaw(vector.direction(pos, pos2))
if abs(tyaw - yaw) > 0.1 then
mobkit.lq_turn2pos(self, pos2)
end
mobkit.lq_dumbwalk(self, pos2, speed_factor)
return true
end
end
function better_fauna.feed_tame(self, clicker, feed_count, tame, breed)
local item = clicker:get_wielded_item()
local pos = self.object:get_pos()
local mob_name = mob_core.get_name_proper(self.name)
if mob_core.follow_holding(self, clicker) then
if creative == false then
item:take_item()
clicker:set_wielded_item(item)
end
mobkit.heal(self, self.max_hp/feed_count)
if self.hp >= self.max_hp then
self.hp = self.max_hp
end
self.food = mobkit.remember(self, "food", self.food + 1)
local minppos = vector.add(pos, hitbox(self)[4])
local maxppos = vector.subtract(pos, hitbox(self)[4])
local def = minetest.registered_items[item:get_name()]
local texture = def.inventory_image
if not texture or texture == "" then
texture = def.wield_image
if def.tiles then
texture = def.tiles[1]
end
end
texture = texture .. "^[resize:8x8" -- Crops image
minetest.add_particlespawner({
amount = 12*self.height,
time = 0.1,
minpos = minppos,
maxpos = maxppos,
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,
minsize = 2*self.height,
maxsize = 3*self.height,
collisiondetection = true,
vertical = false,
texture = texture,
})
if self.food >= feed_count then
self.food = mobkit.remember(self, "food", 0)
if tame and not self.tamed then
mob_core.set_owner(self, clicker:get_player_name())
minetest.chat_send_player(clicker:get_player_name(), mob_name.." has been tamed!")
mobkit.clear_queue_high(self)
paleotest.particle_spawner(pos, "mob_core_green_particle.png", "float", min, max)
end
if breed then
if self.child then return false end
if self.breeding then return false end
if self.breeding_cooldown <= 0 then
self.breeding = true
local min = vector.subtract(pos, 0.5)
local max = vector.add(pos, 0.5)
better_fauna.particle_spawner(pos, "heart.png", "float", min, max)
end
end
end
end
return false
end
------------------
-- HQ Functions --
------------------
function better_fauna.hq_sporadic_flee(self, prty, player)
local tyaw = 0
local init = true
local timer = 1
if not player then return true end
local func = function(self)
if not mobkit.is_alive(player) then return true end
if not mobkit.is_alive(self) then return true end
local pos = mobkit.get_stand_pos(self)
local yaw = self.object:get_yaw()
local tpos = vector.add(pos, vector.multiply(minetest.yaw_to_dir(yaw), 4))
if init then
tyaw = minetest.dir_to_yaw(vector.direction(pos, tpos))
end
if self._anim ~= "run" then
mobkit.animate(self, "run")
end
if mobkit.is_queue_empty_low(self) then
timer = timer - self.dtime
if timer < 0 then
tyaw = yaw - random(1.6, 3.2)
timer = 1
end
if abs(tyaw - yaw) > 0.1 then
mobkit.turn2yaw(self, tyaw)
end
mobkit.go_forward_horizontal(self, self.max_speed)
if timer <= 0 then return true end
end
end
mobkit.queue_high(self, func, prty)
end
function better_fauna.hq_follow_player(self, prty, player) -- Follow Player
if not player then return end
if not mob_core.follow_holding(self, player) then return end
local func = function(self)
if not mobkit.is_alive(player) then
mobkit.clear_queue_high(self)
return true
end
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
local tpos = player:get_pos()
if mob_core.follow_holding(self, player) then
self.status = mobkit.remember(self, "status", "following")
local dist = vec_dist(pos, tpos)
local yaw = self.object:get_yaw()
local tyaw = minetest.dir_to_yaw(vector.direction(pos, tpos))
if dist > self.view_range then
self.status = mobkit.remember(self, "status", "")
return true
end
better_fauna.path_to_next_waypoint(self, tpos, 0.85)
if vec_dist(pos, tpos) < hitbox(self)[4] + 2 then
mobkit.lq_idle(self, 0.1, "stand")
end
else
self.status = mobkit.remember(self, "status", "")
mobkit.lq_idle(self, 0.1, "stand")
return true
end
end
end
mobkit.queue_high(self, func, prty)
end
function better_fauna.get_nearby_mate(self, name)
for _,obj in ipairs(self.nearby_objects) do
if mobkit.is_alive(obj)
and not obj:is_player()
and obj:get_luaentity().name == name
and obj:get_luaentity().gender ~= self.gender
and obj:get_luaentity().breeding then
return obj
end
end
return
end
function better_fauna.hq_breed(self, prty)
local mate = better_fauna.get_nearby_mate(self, self.name)
if not mate then return end
local speed_factor = 0.5
local func = function(self)
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
local tpos = mate:get_pos()
local dist = vec_dist(pos, tpos) - math.abs(hitbox(self)[4])
if dist > 1.5 then
speed_factor = 0.5
else
speed_factor = 0.1
end
mob_core.goto_next_waypoint(self, tpos, speed_factor)
if dist < 1.75 then
self.breeding_time = self.breeding_time + 1
end
if self.breeding_time >= 2
or mate:get_luaentity().breeding_time >= 2 then
if self.gender == "female" then
mob_core.spawn_child(pos, self.name)
end
self.breeding = false
self.breeding_time = 0
self.breeding_cooldown = 300
mobkit.remember(self, "breeding", self.breeding)
mobkit.remember(self, "breeding_time", self.breeding_time)
mobkit.remember(self, "breeding_cooldown", self.breeding_cooldown)
return true
end
end
end
mobkit.queue_high(self, func, prty)
end
function better_fauna.hq_fowl_breed(self, prty)
local mate = better_fauna.get_nearby_mate(self, self.name)
if not mate then return end
local speed_factor = 0.5
local func = function(self)
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
local tpos = mate:get_pos()
local dist = vec_dist(pos, tpos) - math.abs(hitbox(self)[4])
if dist > 1.5 then
speed_factor = 0.5
else
speed_factor = 0.1
end
mob_core.goto_next_waypoint(self, tpos, speed_factor)
if dist < 1.75 then
self.breeding_time = self.breeding_time + 1
end
if self.breeding_time >= 2
or mate:get_luaentity().breeding_time >= 2 then
if self.gender == "female" then
minetest.add_particlespawner({
amount = 6,
time = 0.25,
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 = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
collisiondetection = true,
texture = "better_fauna_egg_fragment.png",
})
mob_core.spawn_child(pos, self.name)
end
self.breeding = false
self.breeding_time = 0
self.breeding_cooldown = 300
mobkit.remember(self, "breeding", self.breeding)
mobkit.remember(self, "breeding_time", self.breeding_time)
mobkit.remember(self, "breeding_cooldown", self.breeding_cooldown)
return true
end
end
end
mobkit.queue_high(self, func, prty)
end
function better_fauna.hq_eat(self, prty)
local func = function(self)
local pos = mobkit.get_stand_pos(self)
local under = vector.new(pos.x, pos.y - 1, pos.z)
for _, node in ipairs(self.consumable_nodes) do
if node.name == minetest.get_node(under).name then
minetest.set_node(under, {name = node.replacement})
local def = minetest.registered_nodes[node.name]
local texture = def.tiles[1]
texture = texture .. "^[resize:8x8"
minetest.add_particlespawner({
amount = 6,
time = 0.1,
minpos = vector.new(
pos.x - 0.5,
pos.y + 0.1,
pos.z - 0.5
),
maxpos = vector.new(
pos.x + 0.5,
pos.y + 0.1,
pos.z + 0.5
),
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,
minsize = 1,
maxsize = 2,
collisiondetection = true,
vertical = false,
texture = texture,
})
self.gotten = false
mobkit.remember(self, "gotten", self.gotten)
return true
else
return true
end
end
end
mobkit.queue_high(self, func, prty)
end
---------------------------------
-- Entity Definition Functions --
---------------------------------
function better_fauna.on_step(self, dtime, moveresult)
mob_core.on_step(self, dtime, moveresult)
if mobkit.timer(self, 1) then
if self.breeding_cooldown > 0 then
self.breeding_cooldown = self.breeding_cooldown - 1
end
mobkit.remember(self, "breeding_cooldown", self.breeding_cooldown)
end
end
function better_fauna.on_activate(self, staticdata, dtime_s)
mob_core.on_activate(self, staticdata, dtime_s)
self.gotten = mobkit.recall(self, "gotten") or false
self.attention_span = mobkit.recall(self, "attention_span") or 0
self.breeding = mobkit.recall(self, "breeding") or false
self.breeding_time = mobkit.recall(self, "breeding_time") or 0
self.breeding_cooldown = mobkit.recall(self, "breeding_cooldown") or 0
end

60
craftitems.lua Normal file
View file

@ -0,0 +1,60 @@
----------------
-- Craftitems --
----------------
---- Ver 0.1 ---
minetest.register_craftitem("better_fauna:net", {
description = "Animal Net",
inventory_image = "better_fauna_net.png",
on_secondary_use = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "object" then
if pointed_thing.ref:is_player() then
return
end
local ent = pointed_thing.ref:get_luaentity()
if not ent.name:match("^better_fauna:")
or not ent.catch_with_net then
return
end
local ent_name = mob_core.get_name_proper(ent.name)
local meta = itemstack:get_meta()
if not meta:get_string("mob")
or meta:get_string("mob") == "" then
meta:set_string("mob", ent.name)
meta:set_string("staticdata", ent:get_staticdata())
local desc = "Animal Net \n" .. minetest.colorize("#a9a9a9", ent_name)
meta:set_string("description", desc)
placer:set_wielded_item(itemstack)
ent.object:remove()
return itemstack
else
minetest.chat_send_player(placer:get_player_name(), "This Net already contains a "..ent_name)
return
end
end
end,
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
})

25
init.lua Normal file
View file

@ -0,0 +1,25 @@
better_fauna = {}
better_fauna.walkable_nodes = {}
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_nodes) do
if name ~= "air" and name ~= "ignore" then
if minetest.registered_nodes[name].walkable then
table.insert(better_fauna.walkable_nodes, name)
end
end
end
end)
local path = minetest.get_modpath("better_fauna")
dofile(path.."/api/api.lua")
dofile(path.."/craftitems.lua")
dofile(path.."/mobs/chicken.lua")
dofile(path.."/mobs/cow.lua")
dofile(path.."/mobs/pig.lua")
dofile(path.."/mobs/sheep.lua")
minetest.log("action", "[MOD] Better Fauna [0.1] loaded")

317
mobs/chicken.lua Normal file
View file

@ -0,0 +1,317 @@
-------------
-- Chicken --
-------------
local min = math.min
local abs = math.abs
local random = math.random
local function chicken_physics(self)
local vel = self.object:get_velocity()
if self.isonground and not self.isinliquid then
self.object:set_velocity({x= vel.x> 0.2 and vel.x*mobkit.friction or 0,
y=vel.y,
z=vel.z > 0.2 and vel.z*mobkit.friction or 0})
end
if self.springiness and self.springiness > 0 then
local vnew = vector.new(vel)
if not self.collided then
for _,k in ipairs({'y','z','x'}) do
if vel[k]==0 and abs(self.lastvelocity[k])> 0.1 then
vnew[k]=-self.lastvelocity[k]*self.springiness
end
end
end
if not vector.equals(vel,vnew) then
self.collided = true
else
if self.collided then
vnew = vector.new(self.lastvelocity)
end
self.collided = false
end
self.object:set_velocity(vnew)
end
local surface = nil
local surfnodename = nil
local spos = mobkit.get_stand_pos(self)
spos.y = spos.y+0.01
local snodepos = mobkit.get_node_pos(spos)
local surfnode = mobkit.nodeatpos(spos)
while surfnode and surfnode.drawtype == 'liquid' do
surfnodename = surfnode.name
surface = snodepos.y+0.5
if surface > spos.y+self.height then break end
snodepos.y = snodepos.y+1
surfnode = mobkit.nodeatpos(snodepos)
end
self.isinliquid = surfnodename
if surface then
local submergence = min(surface-spos.y,self.height)/self.height
local buoyacc = mobkit.gravity*(self.buoyancy-submergence)
mobkit.set_acceleration(self.object,
{x=-vel.x*self.water_drag,y=buoyacc-vel.y*abs(vel.y)*0.4,z=-vel.z*self.water_drag})
else
self.object:set_acceleration({x=0,y=-2.8,z=0})
end
end
local function chicken_logic(self)
if self.hp <= 0 then
mob_core.on_die(self)
return
end
local prty = mobkit.get_queue_priority(self)
local player = mobkit.get_nearby_player(self)
if mobkit.timer(self,1) then
mob_core.vitals(self)
mob_core.random_drop(self, 10, 1800, "better_fauna:chicken_egg")
mob_core.random_sound(self, 8)
if prty < 3
and self.breeding then
better_fauna.hq_fowl_breed(self, 3)
end
if prty < 2
and player then
if self.attention_span < 5 then
if mob_core.follow_holding(self, player) then
better_fauna.hq_follow_player(self, 2, player)
self.attention_span = self.attention_span + 1
end
end
end
if mobkit.is_queue_empty_high(self) then
mob_core.hq_roam(self, 0)
end
end
end
minetest.register_entity("better_fauna:chicken",{
max_hp = 10,
view_range = 16,
armor_groups = {fleshy = 100},
physical = true,
collide_with_objects = true,
collisionbox = {-0.2, -0.15, -0.2, 0.2, 0.3, 0.2},
visual_size = {x = 6, y = 6},
scale_stage1 = 0.25,
scale_stage2 = 0.5,
scale_stage3 = 0.75,
visual = "mesh",
mesh = "better_fauna_chicken.b3d",
female_textures = {
"better_fauna_chicken_1.png",
"better_fauna_chicken_2.png",
"better_fauna_chicken_3.png"
},
male_textures = {
"better_fauna_rooster_1.png",
"better_fauna_rooster_2.png",
"better_fauna_rooster_3.png"
},
child_textures = {"better_fauna_chick.png"},
animation = {
stand = {range = {x = 0, y = 0}, speed = 1, loop = true},
walk = {range = {x = 10, y = 30}, speed = 30, loop = true},
run = {range = {x = 10, y = 30}, speed = 45, loop = true},
fall = {range = {x = 40, y = 60}, speed = 30, loop = true},
},
sounds = {
alter_child_pitch = true,
random = {
name = "better_fauna_chicken_idle",
gain = 1.0,
distance = 8
},
hurt = {
name = "better_fauna_chicken_hurt",
gain = 1.0,
distance = 8
},
death = {
name = "better_fauna_chicken_death",
gain = 1.0,
distance = 8
}
},
max_speed = 4,
stepheight = 1.1,
jump_height = 1.1,
buoyancy = 0.25,
lung_capacity = 10,
timeout = 1200,
ignore_liquidflag = false,
core_growth = false,
push_on_collide = true,
catch_with_net = true,
follow = {
"farming:seed_cotton",
"farming:seed_wheat"
},
drops = {
{name = "better_fauna:feather", chance = 1, min = 1, max = 2},
{name = "better_fauna:chicken_raw", chance = 1, min = 1, max = 4}
},
on_step = better_fauna.on_step,
on_activate = better_fauna.on_activate,
get_staticdata = mobkit.statfunc,
phsyics = chicken_physics,
logic = chicken_logic,
on_rightclick = function(self, clicker)
if better_fauna.feed_tame(self, clicker, 1, false, true) then return end
mob_core.protect(self, clicker, false)
mob_core.nametag(self, clicker, true)
end,
on_punch = function(self, puncher, _, tool_capabilities, dir)
mobkit.clear_queue_high(self)
mob_core.on_punch_basic(self, puncher, tool_capabilities, dir)
better_fauna.hq_sporadic_flee(self, 10, puncher)
end,
})
mob_core.register_spawn_egg("better_fauna:chicken", "753b1f", "5f341f")
mob_core.register_spawn({
name = "better_fauna:chicken",
nodes = {"default:dry_dirt_with_dry_grass", "default:dirt_with_grass"},
min_light = 0,
max_light = 15,
min_height = -31000,
max_height = 31000,
min_rad = 24,
max_rad = 256,
group = 6,
optional = {
biomes = {
"grassland",
"savanna",
"rainforest"
}
}
}, 16, 6)
minetest.register_craftitem("better_fauna:chicken_raw", {
description = "Raw Chicken",
inventory_image = "better_fauna_chicken_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2},
})
minetest.register_craftitem("better_fauna:chicken_cooked", {
description = "Cooked Chicken",
inventory_image = "better_fauna_chicken_cooked.png",
on_use = minetest.item_eat(6),
groups = {flammable = 2},
})
minetest.register_craft({
type = "cooking",
recipe = "better_fauna:chicken_raw",
output = "better_fauna:chicken_cooked",
})
minetest.register_entity("better_fauna:chicken_egg_sprite", {
hp_max = 1,
physical = true,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "sprite",
visual_size = {x = 0.5, y = 0.5},
textures = {"better_fauna_egg.png"},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
on_step = function(self, dtime)
local pos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(pos, 1.5)
local cube = minetest.find_nodes_in_area(
vector.new(pos.x - 0.5, pos.y - 0.5, pos.z - 0.5),
vector.new(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5),
better_fauna.walkable_nodes)
if #objects >= 2 then
if objects[2]:get_armor_groups().fleshy then
objects[2]:punch(self.object, 2.0, {full_punch_interval = 0.1, damage_groups = {fleshy = 1}}, nil)
end
end
if #cube >= 1 then
minetest.add_particlespawner({
amount = 6,
time = 0.25,
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 = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
collisiondetection = true,
texture = "better_fauna_egg_fragment.png",
})
if math.random(1, 3) == 1 then
mob_core.spawn_child(pos, "better_fauna:chicken")
self.object:remove()
else
self.object:remove()
end
end
end
})
local mobs_shoot_egg = function (item, player, pointed_thing)
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 obj = minetest.add_entity({
x = pos.x,
y = pos.y +1.5,
z = pos.z
}, "better_fauna:chicken_egg_sprite")
local ent = obj:get_luaentity()
local dir = player:get_look_dir()
ent.velocity = vel -- needed for api internal timing
ent.switch = 1 -- needed so that egg doesn't despawn straight away
obj:set_velocity({
x = dir.x * vel,
y = dir.y * vel,
z = dir.z * vel
})
obj:set_acceleration({
x = dir.x * -3,
y = -gravity,
z = dir.z * -3
})
-- pass player name to egg for chick ownership
local ent2 = obj:get_luaentity()
ent2.playername = player:get_player_name()
item:take_item()
return item
end
minetest.register_craftitem("better_fauna:chicken_egg", {
description = "Chicken Egg",
inventory_image = "better_fauna_egg.png",
on_use = mobs_shoot_egg,
groups = {flammable = 2},
})

220
mobs/cow.lua Normal file
View file

@ -0,0 +1,220 @@
---------
-- Cow --
---------
local function cow_logic(self)
if self.hp <= 0 then
mob_core.on_die(self)
return
end
local pos = mobkit.get_stand_pos(self)
local prty = mobkit.get_queue_priority(self)
local player = mobkit.get_nearby_player(self)
mob_core.random_sound(self, 16/self.dtime)
if mobkit.timer(self,1) then
mob_core.vitals(self)
mob_core.growth(self)
if math.random(1, 64) == 1 then
self.gotten = mobkit.remember(self, "gotten", false)
end
if self.status ~= "following" then
if self.attention_span > 1 then
self.attention_span = self.attention_span - 1
mobkit.remember(self, "attention_span", self.attention_span)
end
else
self.attention_span = self.attention_span + 1
mobkit.remember(self, "attention_span", self.attention_span)
end
if prty < 4
and self.breeding then
better_fauna.hq_breed(self, 4)
end
if prty < 3
and self.gotten
and math.random(1, 16) == 1 then
better_fauna.hq_eat(self, 3)
end
if prty < 2
and player then
if self.attention_span < 5 then
if mob_core.follow_holding(self, player) then
better_fauna.hq_follow_player(self, 2, player)
self.attention_span = self.attention_span + 1
end
end
end
if mobkit.is_queue_empty_high(self) then
mob_core.hq_roam(self, 0)
end
end
end
local random = math.random
minetest.register_entity("better_fauna:cow",{
max_hp = 20,
view_range = 16,
armor_groups = {fleshy = 100},
physical = true,
collide_with_objects = true,
collisionbox = {-0.45, -0.55, -0.45, 0.45, 0.4, 0.45},
visual_size = {x = 13, y = 13},
scale_stage1 = 0.5,
scale_stage2 = 0.65,
scale_stage3 = 0.80,
visual = "mesh",
mesh = "better_fauna_cow.b3d",
textures = {
"better_fauna_cow_1.png",
"better_fauna_cow_2.png",
"better_fauna_cow_3.png",
"better_fauna_cow_4.png"
},
animation = {
stand = {range = {x = 30, y = 50}, speed = 10, loop = true},
walk = {range = {x = 1, y = 20}, speed = 20, loop = true},
run = {range = {x = 1, y = 20}, speed = 30, loop = true},
},
sounds = {
alter_child_pitch = true,
random = {
name = "better_fauna_cow_idle",
gain = 1.0,
distance = 8
},
hurt = {
name = "better_fauna_cow_hurt",
gain = 1.0,
distance = 8
},
death = {
name = "better_fauna_cow_death",
gain = 1.0,
distance = 8
}
},
max_speed = 4,
stepheight = 1.1,
jump_height = 1.1,
buoyancy = 0.25,
lung_capacity = 10,
timeout = 1200,
ignore_liquidflag = false,
core_growth = false,
push_on_collide = true,
catch_with_net = true,
follow = {
"farming:wheat",
},
drops = {
{name = "mobs:leather", chance = 1, min = 1, max = 2},
{name = "better_fauna:beef_raw", chance = 1, min = 1, max = 4}
},
on_step = better_fauna.on_step,
on_activate = better_fauna.on_activate,
get_staticdata = mobkit.statfunc,
logic = cow_logic,
on_rightclick = function(self, clicker)
if better_fauna.feed_tame(self, clicker, 1, false, true) then return end
mob_core.protect(self, clicker, false)
mob_core.nametag(self, clicker, true)
local tool = clicker:get_wielded_item()
local name = clicker:get_player_name()
if tool:get_name() == "bucket:bucket_empty" then
if self.child == true then
return
end
if self.gotten == true 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 = "better_fauna:bucket_milk"}) then
clicker:get_inventory():add_item("main", "better_fauna:bucket_milk")
else
local pos = self.object:get_pos()
pos.y = pos.y + 0.5
minetest.add_item(pos, {name = "better_fauna:bucket_milk"})
end
self.gotten = mobkit.remember(self, "gotten", true)
return
end
end,
on_punch = function(self, puncher, _, tool_capabilities, dir)
mobkit.clear_queue_high(self)
mob_core.on_punch_basic(self, puncher, tool_capabilities, dir)
better_fauna.hq_sporadic_flee(self, 20, puncher)
end
})
minetest.register_craftitem("better_fauna:bucket_milk", {
description = "Bucket of Milk",
inventory_image = "better_fauna_milk_bucket.png",
stack_max = 1,
on_use = minetest.item_eat(8, "bucket:bucket_empty"),
groups = {food_milk = 1, flammable = 3},
})
minetest.register_craftitem("better_fauna:beef_raw", {
description = "Raw Beef",
inventory_image = "better_fauna_beef_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2},
})
minetest.register_craftitem("better_fauna:beef_cooked", {
description = "Steak",
inventory_image = "better_fauna_beef_cooked.png",
on_use = minetest.item_eat(8),
groups = {flammable = 2},
})
minetest.register_craft({
type = "cooking",
recipe = "better_fauna:beef_raw",
output = "better_fauna:beef_cooked",
})
mob_core.register_spawn_egg("better_fauna:cow", "cac3a1" ,"464438")
mob_core.register_spawn({
name = "better_fauna:cow",
nodes = {
"default:dirt_with_grass",
"default:dry_dirt_with_dry_grass"
},
min_light = 0,
max_light = 15,
min_height = -31000,
max_height = 31000,
group = 3,
optional = {
biomes = {
"grassland",
"savanna"
}
}
}, 4, 6)

166
mobs/pig.lua Normal file
View file

@ -0,0 +1,166 @@
---------
-- Pig --
---------
local function pig_logic(self)
if self.hp <= 0 then
mob_core.on_die(self)
return
end
local pos = mobkit.get_stand_pos(self)
local prty = mobkit.get_queue_priority(self)
local player = mobkit.get_nearby_player(self)
mob_core.random_sound(self, 16/self.dtime)
if mobkit.timer(self,1) then
mob_core.vitals(self)
mob_core.growth(self)
if self.status ~= "following" then
if self.attention_span > 1 then
self.attention_span = self.attention_span - 1
mobkit.remember(self, "attention_span", self.attention_span)
end
else
self.attention_span = self.attention_span + 1
mobkit.remember(self, "attention_span", self.attention_span)
end
if prty < 3
and self.breeding then
better_fauna.hq_breed(self, 3)
end
if prty < 2
and player then
if self.attention_span < 5 then
if mob_core.follow_holding(self, player) then
better_fauna.hq_follow_player(self, 2, player)
self.attention_span = self.attention_span + 1
end
end
end
if mobkit.is_queue_empty_high(self) then
mob_core.hq_roam(self, 0)
end
end
end
local random = math.random
minetest.register_entity("better_fauna:pig",{
max_hp = 20,
view_range = 16,
armor_groups = {fleshy = 100},
physical = true,
collide_with_objects = true,
collisionbox = {-0.45, -0.55, -0.45, 0.45, 0.4, 0.45},
visual_size = {x = 13, y = 13},
scale_stage1 = 0.5,
scale_stage2 = 0.65,
scale_stage3 = 0.80,
visual = "mesh",
mesh = "better_fauna_pig.b3d",
textures = {
"better_fauna_pig_1.png",
"better_fauna_pig_2.png",
"better_fauna_pig_3.png"
},
animation = {
stand = {range = {x = 30, y = 50}, speed = 10, loop = true},
walk = {range = {x = 1, y = 20}, speed = 30, loop = true},
run = {range = {x = 1, y = 20}, speed = 45, loop = true},
},
sounds = {
alter_child_pitch = true,
random = {
name = "better_fauna_pig_idle",
gain = 1.0,
distance = 8
},
hurt = {
name = "better_fauna_pig_idle",
gain = 1.0,
pitch = 0.5,
distance = 8
},
death = {
name = "better_fauna_pig_death",
gain = 1.0,
distance = 8
}
},
max_speed = 4,
stepheight = 1.1,
jump_height = 1.1,
buoyancy = 0.25,
lung_capacity = 10,
timeout = 1200,
ignore_liquidflag = false,
core_growth = false,
push_on_collide = true,
catch_with_net = true,
follow = {
"farming:carrot"
},
drops = {
{name = "better_fauna:porkchop_raw", chance = 1, min = 1, max = 4}
},
on_step = better_fauna.on_step,
on_activate = better_fauna.on_activate,
get_staticdata = mobkit.statfunc,
logic = pig_logic,
on_rightclick = function(self, clicker)
if better_fauna.feed_tame(self, clicker, 1, false, true) then return end
mob_core.protect(self, clicker, false)
mob_core.nametag(self, clicker, true)
end,
on_punch = function(self, puncher, _, tool_capabilities, dir)
mobkit.clear_queue_high(self)
mob_core.on_punch_basic(self, puncher, tool_capabilities, dir)
better_fauna.hq_sporadic_flee(self, 20, puncher)
end
})
minetest.register_craftitem("better_fauna:porkchop_raw", {
description = "Raw Porkchop",
inventory_image = "better_fauna_porkchop_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2},
})
minetest.register_craftitem("better_fauna:porkchop_cooked", {
description = "Cooked Porkchop",
inventory_image = "better_fauna_porkchop_cooked.png",
on_use = minetest.item_eat(7),
groups = {flammable = 2},
})
minetest.register_craft({
type = "cooking",
recipe = "better_fauna:porkchop_raw",
output = "better_fauna:porkchop_cooked",
})
mob_core.register_spawn_egg("better_fauna:pig", "cac3a1" ,"464438")
mob_core.register_spawn({
name = "better_fauna:pig",
nodes = {"default:dirt_with_grass"},
min_light = 0,
max_light = 15,
min_height = -31000,
max_height = 31000,
group = 3,
optional = {
biomes = {
"grassland",
"deciduous_forest"
}
}
}, 16, 1)

274
mobs/sheep.lua Normal file
View file

@ -0,0 +1,274 @@
-----------
-- Sheep --
-----------
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"},
}
local min = math.min
local abs = math.abs
local random = math.random
local function sheep_logic(self)
if self.hp <= 0 then
mob_core.on_die(self)
return
end
local pos = mobkit.get_stand_pos(self)
local prty = mobkit.get_queue_priority(self)
local player = mobkit.get_nearby_player(self)
mob_core.random_sound(self, 16/self.dtime)
if mobkit.timer(self,1) then
mob_core.vitals(self)
mob_core.growth(self)
if self.status ~= "following" then
if self.attention_span > 1 then
self.attention_span = self.attention_span - 1
mobkit.remember(self, "attention_span", self.attention_span)
end
else
self.attention_span = self.attention_span + 1
mobkit.remember(self, "attention_span", self.attention_span)
end
if prty < 4
and self.breeding then
better_fauna.hq_breed(self, 4)
end
if prty < 3
and self.gotten
and math.random(1, 16) == 1 then
better_fauna.hq_eat(self, 3)
end
if prty < 2
and player then
if self.attention_span < 5 then
if mob_core.follow_holding(self, player) then
better_fauna.hq_follow_player(self, 2, player)
self.attention_span = self.attention_span + 1
end
end
end
if mobkit.is_queue_empty_high(self) then
mob_core.hq_roam(self, 0)
end
end
end
minetest.register_entity("better_fauna:sheep",{
max_hp = 20,
view_range = 16,
armor_groups = {fleshy = 100},
physical = true,
collide_with_objects = true,
collisionbox = {-0.4, -0.4, -0.4, 0.4, 0.4, 0.4},
visual_size = {x = 10, y = 10},
scale_stage1 = 0.5,
scale_stage2 = 0.65,
scale_stage3 = 0.80,
visual = "mesh",
mesh = "better_fauna_sheep.b3d",
textures = {"better_fauna_sheep.png^better_fauna_sheep_wool.png"},
child_textures = {"better_fauna_sheep.png"},
animation = {
stand = {range = {x = 30, y = 50}, speed = 10, loop = true},
walk = {range = {x = 1, y = 20}, speed = 30, loop = true},
run = {range = {x = 1, y = 20}, speed = 45, loop = true},
},
sounds = {
alter_child_pitch = true,
random = {
name = "better_fauna_sheep_idle",
gain = 1.0,
distance = 8
},
hurt = {
name = "better_fauna_sheep_idle",
gain = 1.0,
pitch = 0.5,
distance = 8
},
death = {
name = "better_fauna_sheep_idle",
gain = 1.0,
pitch = 0.25,
distance = 8
}
},
max_speed = 4,
stepheight = 1.1,
jump_height = 1.1,
buoyancy = 0.25,
lung_capacity = 10,
timeout = 1200,
ignore_liquidflag = false,
core_growth = false,
push_on_collide = true,
catch_with_net = true,
follow = {
"farming:wheat"
},
drops = {
{name = "better_fauna:mutton_raw", chance = 1, min = 1, max = 4}
},
consumable_nodes = {
{
name = "default:dirt_with_grass",
replacement = "default:dirt"
},
{
name = "default:dry_dirt_with_dry_grass",
replacement = "default:dry_dirt"
}
},
get_staticdata = mobkit.statfunc,
logic = sheep_logic,
on_step = function(self, dtime, moveresult)
better_fauna.on_step(self, dtime, moveresult)
if self.object:get_properties().textures[1] == "better_fauna_sheep.png"
and not self.gotten then
self.object:set_properties({
textures = {"better_fauna_sheep.png^better_fauna_sheep_wool.png"},
})
end
end,
on_activate = function(self, staticdata, dtime_s)
better_fauna.on_activate(self, staticdata, dtime_s)
self.dye_color = mobkit.recall(self, "dye_color") or "white"
self.dye_hex = mobkit.recall(self, "dye_hex") or ""
if self.dye_color ~= "white"
and not self.gotten then
self.object:set_properties({
textures = {"better_fauna_sheep.png^(better_fauna_sheep_wool.png^[colorize:" .. self.dye_hex .. ")"},
})
end
if self.gotten then
self.object:set_properties({
textures = {"better_fauna_sheep.png"},
})
end
end,
on_rightclick = function(self, clicker)
if better_fauna.feed_tame(self, clicker, 1, false, true) then return end
mob_core.protect(self, clicker, false)
mob_core.nametag(self, clicker, true)
local item = clicker:get_wielded_item()
local itemname = item:get_name()
local name = clicker:get_player_name()
if itemname == "mobs:shears"
and not self.gotten
and not self.child then
if not minetest.get_modpath("wool") then
return
end
local obj = minetest.add_item(
self.object:get_pos(),
ItemStack( "wool:" .. self.dye_color .. " " .. math.random(1, 3) )
)
self.gotten = mobkit.remember(self, "gotten", true)
self.dye_color = mobkit.remember(self, "dye_color", "white")
self.dye_hex = mobkit.remember(self, "dye_hex", "#abababc000")
item:add_wear(650) -- 100 uses
clicker:set_wielded_item(item)
self.object:set_properties({
textures = {"better_fauna_sheep.png"},
})
end
for _, color in ipairs(palette) do
if itemname:find("dye:")
and not self.gotten
and not self.child then
local dye = string.split(itemname, ":")[2]
if color[1] == dye then
self.dye_color = mobkit.remember(self, "dye_color", color[1])
self.dye_hex = mobkit.remember(self, "dye_hex", color[3])
self.drops = {
{name = "better_fauna:mutton_raw", chance = 1, min = 1, max = 4},
{name = "wool:"..self.dye_color, chance = 2, min = 1, max = 2},
}
self.object:set_properties({
textures = {"better_fauna_sheep.png^(better_fauna_sheep_wool.png^[colorize:" .. color[3] .. ")"},
})
if not mobs.is_creative(clicker:get_player_name()) then
item:take_item()
clicker:set_wielded_item(item)
end
break
end
end
end
end,
on_punch = function(self, puncher, _, tool_capabilities, dir)
mobkit.clear_queue_high(self)
mob_core.on_punch_basic(self, puncher, tool_capabilities, dir)
better_fauna.hq_sporadic_flee(self, 10, puncher)
end,
})
mob_core.register_spawn_egg("better_fauna:sheep", "f4e6cf", "e1ca9b")
mob_core.register_spawn({
name = "better_fauna:sheep",
nodes = {"default:dirt_with_grass"},
min_light = 0,
max_light = 15,
min_height = -31000,
max_height = 31000,
min_rad = 24,
max_rad = 256,
group = 6
}, 2, 8)
minetest.register_craftitem("better_fauna:mutton_raw", {
description = "Raw Mutton",
inventory_image = "better_fauna_mutton_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2},
})
minetest.register_craftitem("better_fauna:mutton_cooked", {
description = "Cooked Mutton",
inventory_image = "better_fauna_mutton_cooked.png",
on_use = minetest.item_eat(6),
groups = {flammable = 2},
})
minetest.register_craft({
type = "cooking",
recipe = "better_fauna:mutton_raw",
output = "better_fauna:mutton_cooked",
})

3
mod.conf Normal file
View file

@ -0,0 +1,3 @@
name = better_fauna
depends = mobkit, mob_core, default
description = Basic Fauna for Minetest Game

Binary file not shown.

BIN
models/better_fauna_cow.b3d Normal file

Binary file not shown.

BIN
models/better_fauna_pig.b3d Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB