diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..c9a9cc9 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,15 @@ +max_line_length = 120 + +globals = { + "minetest", + "animalia", + "creatura", +} + +read_globals = { + "vector", + "ItemStack", + table = {fields = {"copy"}} +} + +ignore = {"212/self", "212/this"} \ No newline at end of file diff --git a/api/api.lua b/api/api.lua index 2024346..56edac8 100644 --- a/api/api.lua +++ b/api/api.lua @@ -222,6 +222,8 @@ 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 @@ -235,7 +237,7 @@ function animalia.set_nametag(self, clicker) self.nametag = self:memorize("nametag", name) self.despawn_after = self:memorize("despawn_after", nil) activate_nametag(self) - if not creative then + if not minetest.is_creative_enabled(plyr_name) then item:take_item() clicker:set_wielded_item(item) end @@ -449,6 +451,13 @@ function animalia.do_growth(self, interval) 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) self.trust_cooldown = 60 local plyr_name = player:get_player_name() @@ -459,9 +468,11 @@ function animalia.add_trust(self, player, amount) end function animalia.feed(self, player, tame, breed) + local plyr_name = clicker and clicker:get_player_name() + if not plyr_name then return end local item, item_name = self:follow_wielded_item(player) if item_name then - if not creative then + if not minetest.is_creative_enabled(plyr_name) then item:take_item() player:set_wielded_item(item) end @@ -538,10 +549,9 @@ function animalia.mount(self, player, params) animate_player(player, "sit", 30) end self.rider = player - local mob_size = self.object:get_properties().visual_size - local player_size = player:get_properties().visual_size player:set_attach(self.object, "Torso", params.pos, params.rot) player:set_eye_offset({x = 0, y = 25, z = 0}, {x = 0, y = 15, z = 15}) + self:clear_utility() end -------------- @@ -682,592 +692,4 @@ animalia.register_biome_group("common", { min_humidity = 20, max_humidity = 80, min_height = 1 -}) - ---------------- --- Libri API -- ---------------- - -local function contains_item(inventory, item) - return inventory and inventory:contains_item("main", ItemStack(item)) -end - -function animalia.get_libri(inventory) - local list = inventory:get_list("main") - for i = 1, inventory:get_size("main") do - local stack = list[i] - if stack:get_name() - and stack:get_name() == "animalia:libri_animalia" then - return stack, i - end - end -end - -local get_libri = animalia.get_libri - -function animalia.add_libri_page(self, player, page) - local inv = minetest.get_inventory({type = "player", name = player:get_player_name()}) - if contains_item(inv, "animalia:libri_animalia") then - local libri, list_i = get_libri(inv) - local pages = minetest.deserialize(libri:get_meta():get_string("pages")) or {} - if #pages > 0 then - local add_page = true - for i = 1, #pages do - if pages[i].name == page.name then - add_page = false - break - end - end - if add_page then - table.insert(pages, page) - libri:get_meta():set_string("pages", minetest.serialize(pages)) - inv:set_stack("main", list_i, libri) - return true - end - else - table.insert(pages, page) - libri:get_meta():set_string("pages", minetest.serialize(pages)) - inv:set_stack("main", list_i, libri) - return true - end - end -end - -function animalia.get_item_list(list, offset_x, offset_y) -- Creates a visual list of items for Libri formspecs - local size = 1 / #list - if size < 0.45 then size = 0.45 end - local spacing = 0.3 - local total_scale = size + spacing - local max_horiz = 3 - local form = {} - for i = 1, #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 ) - table.insert(form, "item_image[" .. pos_x .. "," .. pos_y .. ";" .. size .. "," .. size .. ";" .. list[i] .. "]") - end - return table.concat(form, "") -end - -local function get_inventory_cube(name) - local def = minetest.registered_nodes[name] - local tiles - if name:find(".png") then - tiles = { - name, - name, - name - } - elseif def then - tiles = table.copy(def.tiles) or table.copy(def.textures) - else - return - end - if not tiles - or type(tiles) ~= "table" - or #tiles < 1 then - return - end - for i = 1, #tiles do - if type(tiles[i]) == "table" then - tiles[i] = tiles[i].name - end - end - local cube - if #tiles < 3 then - cube = minetest.inventorycube(tiles[1], tiles[1], tiles[1]) - else - cube = minetest.inventorycube(tiles[1], tiles[3], tiles[3]) - end - return cube -end - -local function get_textures(name) - local def = minetest.registered_entities[name] - local textures = def.textures - if not textures then - if #def.female_textures < 2 then - textures = {def.female_textures[1], def.male_textures[1]} - else - textures = {} - local num = #def.female_textures - for i = 1, num do - if num + #def.male_textures < 7 then - textures = {unpack(def.male_textures), unpack(def.female_textures)} - else - if i < num * 0.5 then - table.insert(textures, def.female_textures[i]) - else - table.insert(textures, def.male_textures[i]) - end - end - end - end - end - return textures -end - -local animalia_libri_info = {} - -local libri_animal_info = { - ["animalia:bat"] = { - invcube = "default:stone", - info = { - domestication = { - "While they can't be truly", - "domesticated, Bats will begin ", - "to trust you if you feed them ", - "often. A Bat that trusts you will ", - "not flee when you walk near it.", - "This is useful as it allows ", - "Players to keep them around ", - "to harvest their guano, which ", - "can be used as a powerful ", - "fertilizer." - }, - behavior = { - "Bats are mostly harmless, and ", - "can be found hanging from ", - "trees and cliff ceilings during ", - "the day. The only harm they ", - "can cause it to property, with ", - "guano accumulating ", - "underneath them while they ", - "rest. Being social creatures, it's ", - "not uncommon to see a few ", - "hanging from ceilings together ", - "or swarming, which often ", - "occurs at evening or when a ", - "Player approaches." - } - } - }, - ["animalia:bird"] = { - info = { - domestication = { - "Cannot be tamed.", - }, - behavior = { - "Song Birds are found across ", - "various biomes, except for ", - "biomes too inhospitable like ", - "deserts or tundras. They fly in ", - "flocks that vary in size from 4 ", - "or 5 individuals to large flocks ", - "exceeding a dozen individuals. ", - "Their calls vary between ", - "species, making it easy to tell ", - "what kind of birds are around." - } - } - }, - ["animalia:cat"] = { - info = { - domestication = { - "Unlike Wolves and Horses," , - "which are almost immediately ", - "trusting upon being tamed, ", - "Cats will remain untrusting ", - "until you gain their trust. To do ", - "so, you must feed and play ", - "with it often. As trust builds ", - "the cat will become more ", - "comfortable in your presence, ", - "and will be more receptive to ", - "commands.", - }, - behavior = { - "Cats are very annoying ", - "animals, to the point that ", - "some may even call them a ", - "pest. Their behavior in the ", - "wild is somehow more tame ", - "than their domesticated ", - "behavior. They find immense ", - "joy in running front of their ", - "owner and even destroying ", - "glass vessels. Despite this, ", - "they are an incredibly popular ", - "pet, especially for those who ", - "don't often leave their home. ", - "Like Wolves, a tamed Cat will ", - "follow commands, but only if it ", - "highly trusts it's owner." - } - } - }, - ["animalia:chicken"] = { - info = { - domestication = { - "Chickens are very valuable as a ", - "livestock. They're a good ", - "source of meat, but also lay ", - "eggs. This, paired with their ", - "small size, makes them great ", - "for farming with limited space." - }, - behavior = { - "Chickens, or Jungle Fowl, are ", - "most often found in groups. ", - "They exhibit gender ", - "dimorphism to a high degree, ", - "with males having large tail ", - "feathers. In the wild, they ", - "dwell jungle floors, picking up ", - "seeds and insects." - } - } - }, - ["animalia:cow"] = { - info = { - domestication = { - "Cows are commonplace on ", - "farms because of their many ", - "uses. They can be slaughtered ", - "for beef and leather, and ", - "females can be milked. Beef is ", - "one of the most valuable ", - "meats because of how much ", - "satiation it provides, and ", - "leather is valuable for crafting ", - "various items." - }, - behavior = { - "Cows are always found in ", - "groups of 3+ individuals. ", - "Despite being capable of ", - "inflicting damage, they will ", - "always choose to flee, even ", - "when in a large group. They ", - "exhibit gender dimorphism, ", - "with females having udders on ", - "their belly." - }, - } - }, - ["animalia:frog"] = { - info = { - domestication = { - "Cannot be tamed.", - }, - behavior = { - "Frogs are small creatures ", - "almost exclusively found near ", - "bodies of water. They will flee ", - "to nearby water when a Player ", - "approaches. They have quite ", - "an affinity for water, moving ", - "faster while in it and only ", - "being able to breed when ", - "submerged. They come to land ", - "to search for food, which they ", - "catch with their long tongue." - }, - } - }, - ["animalia:horse"] = { - info = { - domestication = { - "Horses are one of the most ", - "valuable animals to ", - "domesticate because of their ", - "ability carry Players and ", - "maintain speed. They can ", - "make traversing the world far ", - "faster and easier, but aren't ", - "easy to tame. To tame one, ", - "you must keep your line of ", - "sight lined up with the Horses ", - "for a varying period of time. ", - "This process is difficult but ", - "well worth it." - }, - behavior = { - "Horses live in large groups, ", - "wandering open grasslands. ", - "They have a number of colors ", - "and patterns, which are passed ", - "down to their offspring, as ", - "well as varying jumping and ", - "running abilities." - }, - } - }, - ["animalia:reindeer"] = { - info = { - domestication = { - "Cannot be tamed.", - }, - behavior = { - "Reindeer are found in large ", - "groups in cold regions. They ", - "stick tightly togther and move ", - "in coordinated directions, even ", - "while fleeing. They're also a ", - "common food source for those ", - "lost in taigas and tundras." - } - } - }, - ["animalia:pig"] = { - info = { - domestication = { - "Pigs are not quite as versatile ", - "as other livestock like Cows or ", - "Chickens, with their only ", - "valuable resource being pork. ", - "But they have a distinct ", - "advantage by being able to ", - "have more offspring at once ", - "than Cows while also being ", - "smaller." - }, - behavior = { - "Pigs in the wild can be very ", - "destructive of ecosystems if ", - "not controlled. Their ability to ", - "reproduce quickly means ", - "keeping populations under ", - "control can be an issue. They ", - "are known to destroy farmland ", - "and will go as far as destroying ", - "fences to do so." - }, - } - }, - ["animalia:sheep"] = { - info = { - domestication = { - "Sheep are one of the most ", - "useful animals to domesticate. ", - "Their wool is a great resource ", - "for crafting and building, and is ", - "entirely renewable. Their wool ", - "can also be dyed, though there ", - "is little use for this." - }, - behavior = { - "Sheep are well known for ", - "living in large groups. In the ", - "wild these groups range from 4 ", - "to 8 individuals, larger than ", - "most other animals." - } - } - }, - ["animalia:tropical_fish"] = { - special_models = { - [3] = "animalia_angelfish.b3d" - }, - info = { - domestication = { - "Cannot be tamed." - }, - behavior = { - "All varieties of Tropical Fish ", - "can be found in schools around ", - "reefs. While they don't ", - "provide food or any resources, ", - "they are a beautiful sight to ", - "see while traversing oceans." - }, - } - }, - ["animalia:turkey"] = { - info = { - domestication = { - "Even though Turkeys take up ", - "more space than Chickens, ", - "they also produce more meat, ", - "at the cost of laying less eggs. ", - "This makes them a good option ", - "for those who don't want to ", - "build a farm large enough to ", - "support Cows or other large ", - "livestock but also don't need ", - "many eggs." - }, - behavior = { - "Turkeys are similar ", - "behaviorally to Chickens, but ", - "spawn in colder biomes and ", - "are slightly larger. They exhibit ", - "gender dimorphism, with ", - "males having a large fan of ", - "feathers on their tail." - } - } - }, - ["animalia:wolf"] = { - info = { - domestication = { - "Their intelligence allows them ", - "not only to form tight bonds ", - "with players, but to also obey ", - "orders. Once ordered to attack ", - "a target, they will pursue it and ", - "attack relentlessly, even if ", - "death certain." - }, - behavior = { - "Wolves are found in packs of ", - "up to 3. They hunt down Sheep ", - "as a group and can quickly ", - "overwhelm their target with ", - "numbers. They're also ", - "remarkebly intelligent, and ", - "will remember players who ", - "have harmed them and will ", - "attack them on sight." - } - } - } -} - --- Libri Utilities -- - -local function offset_info_text(offset_x, offset_y, tbl) - local info_text = {} - for i = 1, #tbl do - local str = tbl[i] - local center_offset = 0 - if string.len(str) < 30 then - center_offset = (30 - string.len(str)) * 0.05 - end - str = minetest.colorize("#383329", str .. "\n") - table.insert(info_text, "label[" .. offset_x + center_offset .. "," .. offset_y + i * 0.25 .. ";" .. str .. "]") - end - return table.concat(info_text, "") -end - -local function get_libri_page(mob_name, player_name) - local def = minetest.registered_entities[mob_name] - local animal_info = libri_animal_info[mob_name] - -- Get Inventory Cube and Mob Texture - local biome_groups = animalia.registered_biome_groups - local biome_group = spawn_biomes[mob_name] - local spawn_biome = biome_groups[biome_group].biomes[animalia_libri_info[player_name].biome_idx] or "grassland" - local invcube - if not minetest.registered_biomes[spawn_biome] - or not minetest.registered_biomes[spawn_biome].node_top then - invcube = get_inventory_cube("unknown_node.png") - else - invcube = get_inventory_cube(animal_info.invcube or minetest.registered_biomes[spawn_biome].node_top) - end - local texture = get_textures(mob_name)[animalia_libri_info[player_name].texture_idx] - local mesh = def.mesh - if libri_animal_info[mob_name].special_models - and libri_animal_info[mob_name].special_models[animalia_libri_info[player_name].texture_idx] then - mesh = libri_animal_info[mob_name].special_models[animalia_libri_info[player_name].texture_idx] - end - -- Create Formspec - local form = { - -- Background - "formspec_version[3]", - "size[16,10]", - "background[-0.7,-0.5;17.5,11.5;animalia_libri_bg.png]", - "image[-0.7,-0.5;17.5,11.5;animalia_libri_info_fg.png]", - -- Mesh - "model[1.5,1.5;5,5;libri_mesh;" .. mesh .. ";" .. texture .. ";-30,225;false;false;0,0;0]", - -- Spawn Biome Group - "image[0.825,8.15;1,1;" .. invcube .. "]", - "tooltip[0.825,8.15;1,1;" .. correct_name(spawn_biome) .. "]", - -- Health - "image[2.535,8.15;1,1;animalia_libri_health_fg.png]", - "label[3.25,9;x" .. def.max_health / 2 .. "]", - -- Net - "item_image[4.25,8.15;1,1;animalia:lasso]", - "image[4.75,8.75;0.5,0.5;animalia_libri_" .. tostring(def.catch_with_lasso or false) .. "_icon.png]", - -- Lasso - "item_image[6,8.15;1,1;animalia:net]", - "image[6.5,8.75;0.5,0.5;animalia_libri_" .. tostring(def.catch_with_net or false) .. "_icon.png]", - -- Labels - "label[9.5,7.25;" .. minetest.colorize("#383329", "Drops:") .. "]", - "label[14,7.25;" .. minetest.colorize("#383329", "Eats:") .. "]", - -- Info Text - "label[9.25,1.5;" .. minetest.colorize("#000000", "Domestication:") .. "]", - "label[13.5,1.5;" .. minetest.colorize("#000000", "Behavior:") .. "]", - } - -- Mob Info - if libri_animal_info[mob_name] then - if libri_animal_info[mob_name].info.domestication then - table.insert(form, offset_info_text(8.5, 2, libri_animal_info[mob_name].info.domestication)) - end - if libri_animal_info[mob_name].info.behavior then - table.insert(form, offset_info_text(12.5, 2, libri_animal_info[mob_name].info.behavior)) - end - end - if def.follow then - table.insert(form, animalia.get_item_list(def.follow, 12.35, 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, animalia.get_item_list(drops, 8, 8.05)) - end - return table.concat(form, "") -end - -local function update_libri(player_name, mob_name) - if not animalia_libri_info[player_name] - or animalia_libri_info[player_name].name ~= mob_name then - return - end - local texture_idx = animalia_libri_info[player_name].texture_idx or 1 - local biome_idx = animalia_libri_info[player_name].biome_idx or 1 - if texture_idx >= #get_textures(mob_name) then - texture_idx = 1 - else - texture_idx = texture_idx + 1 - end - local wild_biomes = animalia.registered_biome_groups[spawn_biomes[mob_name]].biomes - if biome_idx >= #wild_biomes then - biome_idx = 1 - else - biome_idx = biome_idx + 1 - end - animalia_libri_info[player_name] = { - texture_idx = texture_idx, - biome_idx = biome_idx, - name = mob_name - } - minetest.show_formspec(player_name, "animalia:libri_" .. mob_name:split(":")[2], get_libri_page(mob_name, player_name)) - minetest.after(4, function() - update_libri(player_name, mob_name) - end) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - local player_name = player:get_player_name() - if formname == "animalia:libri_main" then - animalia_libri_info[player_name] = {} - for i = 1, #animalia.animals do - local name = animalia.animals[i]:split(":")[2] - if fields["pg_" .. name] then - -- Get data for mob and biome visuals - animalia_libri_info[player_name] = { - texture_idx = 1, - biome_idx = 1, - name = animalia.animals[i] - } - update_libri(player_name, animalia.animals[i]) - break - end - end - if fields["btn_next"] then - local pages = animalia.libri_pages[player_name] - if pages - and #pages > 1 then - animalia.show_libri_main_form(player, pages, 2) - end - end - end - if formname:match("^animalia:libri_") then - if fields.quit or fields.key_enter then - animalia_libri_info[player_name] = nil - end - end -end) \ No newline at end of file +}) \ No newline at end of file diff --git a/api/behaviors.lua b/api/behaviors.lua index bbdb4a1..967ef18 100644 --- a/api/behaviors.lua +++ b/api/behaviors.lua @@ -50,6 +50,15 @@ local yaw2dir = minetest.yaw_to_dir -- Local Tools -- ----------------- +local animate_player = {} + +if minetest.get_modpath("default") +and minetest.get_modpath("player_api") then + animate_player = player_api.set_animation +elseif minetest.get_modpath("mcl_player") then + animate_player = mcl_player.set_animation +end + local get_collision = creatura.get_collision local function get_avoidance_dir(self) @@ -114,6 +123,40 @@ end -------------- creatura.register_movement_method("animalia:fly_simple", function(self) + local box = clamp(self.width, 0.5, 1.5) + self:set_gravity(0) + local function func(_self, goal, speed_factor) + local pos = _self.object:get_pos() + if not pos then return end + -- Return true when goal is reached + if vec_dist(pos, goal) < box * 1.33 then + _self:halt() + return true + end + -- Get movement direction + local goal_dir = vec_dir(pos, goal) + local yaw = _self.object:get_yaw() + local goal_yaw = dir2yaw(goal_dir) + local speed = abs(_self.speed or 2) * speed_factor or 0.5 + local turn_rate = abs(_self.turn_rate or 5) + -- Movement + local yaw_diff = abs(diff(yaw, goal_yaw)) + if yaw_diff < pi * 0.25 then + _self:set_forward_velocity(speed) + else + _self:set_forward_velocity(speed * 0.33) + end + self:set_vertical_velocity(speed * goal_dir.y) + _self:turn_to(goal_yaw, turn_rate) + if _self.touching_ground + or _self.in_liquid then + _self.object:add_velocity({x = 0, y = 2, z = 0}) + end + end + return func +end) + +creatura.register_movement_method("animalia:fly_obstacle_avoidance", function(self) local box = clamp(self.width, 0.5, 1.5) local steer_to local steer_timer = 0.25 @@ -159,6 +202,36 @@ creatura.register_movement_method("animalia:fly_simple", function(self) end) creatura.register_movement_method("animalia:swim_simple", function(self) + local box = clamp(self.width, 0.5, 1.5) + self:set_gravity(0) + local function func(_self, goal, speed_factor) + local pos = _self.object:get_pos() + if not pos then return end + -- Return true when goal is reached + if vec_dist(pos, goal) < box * 1.33 then + _self:halt() + return true + end + -- Get movement direction + local goal_dir = vec_dir(pos, goal) + local yaw = _self.object:get_yaw() + local goal_yaw = dir2yaw(goal_dir) + local speed = abs(_self.speed or 2) * speed_factor or 0.5 + local turn_rate = abs(_self.turn_rate or 5) + -- Movement + local yaw_diff = abs(diff(yaw, goal_yaw)) + if yaw_diff < pi * 0.25 then + _self:set_forward_velocity(speed) + else + _self:set_forward_velocity(speed * 0.33) + end + self:set_vertical_velocity(speed * goal_dir.y) + _self:turn_to(goal_yaw, turn_rate) + end + return func +end) + +creatura.register_movement_method("animalia:swim_obstacle_avoidance", function(self) local box = clamp(self.width, 0.5, 1.5) local steer_to local steer_timer = 0.25 @@ -234,7 +307,7 @@ function animalia.action_pursue(self, target, timeout, method, speed_factor, ani self:set_action(func) end -function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, anim) +function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, anim, boid_steer) local old_boids = (self._movement_data and self._movement_data.boids) or {} local boids = (#old_boids > 2 and old_boids) or creatura.get_boid_members(self.object:get_pos(), 12, self.name) local timer = timeout or 4 @@ -265,6 +338,14 @@ function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, a end end end + local steer_to = boid_steer and get_avoidance_dir(self) + if steer_to then + boid_pos2 = { + x = pos.x + steer_to.x * 2, + y = pos2.y, + z = pos.z + steer_to.z * 2 + } + end -- Main movement if timer <= 0 or not safe @@ -308,26 +389,29 @@ end function animalia.action_punch(self, target) local jump_init = false + local timeout = 2 local function func(_self) local tgt_alive, _, tgt_pos = _self:get_target(target) if not tgt_alive then return true end local pos = _self.object:get_pos() if not pos then return end local dir = vec_dir(pos, tgt_pos) - if not jump_init then - local vel = { - x = dir.x * 3, - y = 3, - z = dir.z * 3 - } - _self.object:add_velocity(vel) + if not jump_init + and _self.touching_ground then + _self.object:add_velocity({x = dir.x * 3, y = 2, z = dir.z * 3}) jump_init = true - elseif _self.touching_ground then - return true end + timeout = timeout - _self.dtime + if timeout <= 0 then return true end local dist = vec_dist(pos, tgt_pos) if dist < _self.width + 1 then _self:punch_target(target) + local knockback = minetest.calculate_knockback( + target, self.object, 1.0, + {damage_groups = {fleshy = self.damage}}, + dir, 2.0, self.damage + ) + target:add_velocity({x = dir.x * knockback, y = dir.y * knockback, z = dir.z * knockback}) return true end end @@ -452,8 +536,8 @@ end) -- Wandering creatura.register_utility("animalia:wander", function(self) - local move_chance = 5 - local idle_duration = 4 + local move_chance = self.move_chance or 5 + local idle_duration = self.idle_time or 4 local center = self.object:get_pos() if not center then return end local move = self.wander_action or creatura.action_move @@ -472,8 +556,8 @@ creatura.register_utility("animalia:wander", function(self) end) creatura.register_utility("animalia:wander_group", function(self) - local move_chance = 3 - local idle_duration = 3 + local move_chance = self.move_chance or 3 + local idle_duration = self.idle_time or 3 local center = self.object:get_pos() if not center then return end local group_tick = 500 @@ -491,7 +575,7 @@ creatura.register_utility("animalia:wander_group", function(self) local pos2 = _self:get_wander_pos(2, 3) if random(move_chance) < 2 and vec_dist(pos2, center) < _self.tracking_range * 0.5 then - move(_self, pos2, 2) + move(_self, pos2, 2, "creatura:obstacle_avoidance", 0.5, "walk", true) else creatura.action_idle(_self, random(idle_duration)) end @@ -501,8 +585,8 @@ creatura.register_utility("animalia:wander_group", function(self) end) creatura.register_utility("animalia:wander_skittish", function(self) - local move_chance = 3 - local idle_duration = 3 + local move_chance = self.move_chance or 3 + local idle_duration = self.idle_time or 3 local center = self.object:get_pos() if not center then return end local plyr_tick = 500 @@ -551,7 +635,7 @@ creatura.register_utility("animalia:aerial_wander", function(self) if not _self:get_action() then local move_dir = (vec_dist(pos, center) > 8 and vec_dir(pos, center)) or nil local pos2 = _self:get_wander_pos_3d(2, 5, move_dir) - animalia.action_move_flock(_self, pos2, 3, "animalia:fly_simple", 1, "fly") + animalia.action_move_flock(_self, pos2, 3, "animalia:fly_simple", 1, "fly", true) end end self:set_utility(func) @@ -615,7 +699,7 @@ creatura.register_utility("animalia:aquatic_wander_school", function(self) water_nodes = minetest.find_nodes_in_area(vec_sub(center, 4), vec_add(center, 4), {"group:water"}) end if not _self:get_action() then - animalia.action_move_flock(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_simple", 1, "swim") + animalia.action_move_flock(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_simple", 1, "swim", true) end end self:set_utility(func) @@ -641,7 +725,7 @@ creatura.register_utility("animalia:aquatic_wander", function(self) end if not _self:get_action() then if random(move_chance) < 2 then - creatura.action_move(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_simple", 0.5, "swim") + creatura.action_move(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_obstacle_avoidance", 0.5, "swim") else animalia.action_float(_self, random(idle_duration), "float") end @@ -811,12 +895,35 @@ end) creatura.register_utility("animalia:tame_horse", function(self) local center = self.object:get_pos() local trust = 5 + local player = self.rider + local player_props = player and player:get_properties() + if not player_props then return end + local player_size = player_props.visual_size + local mob_size = self.visual_size + local adj_size = { + x = player_size.x / mob_size.x, + y = player_size.y / mob_size.y + } + if player_size.x ~= adj_size.x then + player:set_properties({ + visual_size = adj_size + }) + end local function func(_self) local pos = _self.object:get_pos() if not pos then return end if not _self.rider or not creatura.is_alive(_self.rider) then return true end - local player = _self.rider + player = _self.rider + animate_player(player, "sit", 30) + if _self:timer(1) then + player_props = player and player:get_properties() + if player_props.visual_size.x ~= adj_size.x then + player:set_properties({ + visual_size = adj_size + }) + end + end if not _self:get_action() then if random(6) < 2 then creatura.action_idle(_self, 0.5, "punch_aoe") @@ -847,6 +954,11 @@ creatura.register_utility("animalia:tame_horse", function(self) animalia.particle_spawner(pos, "creatura_particle_green.png", "float", min_pos, max_pos) return true end + if not player + or player:get_player_control().sneak then + animalia.mount(_self, player) + return true + end end self:set_utility(func) end) @@ -898,7 +1010,7 @@ creatura.register_utility("animalia:breed", function(self) animalia.particle_spawner(pos, "heart.png", "float", minp, maxp) for _ = 1, _self.birth_count or 1 do if _self.add_child then - _self:add_child() + _self:add_child(mate) else local object = minetest.add_entity(pos, _self.name) local ent = object:get_luaentity() @@ -1010,13 +1122,19 @@ creatura.register_utility("animalia:bother_player", function(self, player) end) creatura.register_utility("animalia:mount_horse", function(self, player) - if not player or not player:get_properties() then return end - local player_size = player:get_properties().visual_size + local player_props = player and player:get_properties() + if not player_props then return end + local player_size = player_props.visual_size local mob_size = self.visual_size local adj_size = { x = player_size.x / mob_size.x, y = player_size.y / mob_size.y } + if player_size.x ~= adj_size.x then + player:set_properties({ + visual_size = adj_size + }) + end local function func(_self) if not creatura.is_alive(player) then return true @@ -1027,8 +1145,9 @@ creatura.register_utility("animalia:mount_horse", function(self, player) local control = player:get_player_control() local vel = _self.object:get_velocity() if not tyaw then return end + animate_player(player, "sit", 30) if _self:timer(1) then - local player_props = player:get_properties() + player_props = player and player:get_properties() if player_props.visual_size.x ~= adj_size.x then player:set_properties({ visual_size = adj_size @@ -1044,14 +1163,15 @@ creatura.register_utility("animalia:mount_horse", function(self, player) end end if control.jump - and _self.touching_ground then + and _self.touching_ground + and vel.y < 1 then _self.object:add_velocity({ x = 0, y = _self.jump_power + (abs(_self._movement_data.gravity) * 0.33), z = 0 }) elseif not _self.touching_ground then - speed_x = speed_x * 0.5 + speed_x = speed_x * 0.75 end if not _self.touching_ground and not _self.in_liquid @@ -1060,7 +1180,7 @@ creatura.register_utility("animalia:mount_horse", function(self, player) end local yaw = self.object:get_yaw() if abs(yaw - tyaw) > 0.1 then - _self:turn_to(tyaw) + _self:turn_to(tyaw, _self.turn_rate) end _self:set_forward_velocity(_self.speed * speed_x) _self:animate(anim) diff --git a/api/libri.lua b/api/libri.lua new file mode 100644 index 0000000..0860514 --- /dev/null +++ b/api/libri.lua @@ -0,0 +1,586 @@ +----------- +-- Libri -- +----------- + +local libri = {} + +local path = minetest.get_modpath(minetest.get_current_modname()) + +local color = minetest.colorize + +local page_spacing = 0.5 + +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:bird"] = "Song Bird", + ["animalia:cat"] = "Cat", + ["animalia:chicken"] = "Chicken", + ["animalia:cow"] = "Cow", + --["animalia:tropical_fish"] = "Tropical Fish", + ["animalia:frog"] = "Frog", + ["animalia:horse"] = "Horse", + ["animalia:pig"] = "Pig", + ["animalia:reindeer"] = "Reindeer", + ["animalia:sheep"] = "Sheep", + ["animalia:turkey"] = "Turkey", + ["animalia:wolf"] = "Wolf", +} + + +local spawn_biomes = { + ["animalia:bat"] = "cave", + ["animalia:bird"] = "temperate", + ["animalia:cat"] = "urban", + ["animalia:chicken"] = "tropical", + ["animalia:cow"] = "grassland", + ["animalia:tropical_fish"] = "ocean", + ["animalia:frog"] = "swamp", + ["animalia:horse"] = "grassland", + ["animalia:pig"] = "temperate", + ["animalia:reindeer"] = "boreal", + ["animalia:sheep"] = "grassland", + ["animalia:turkey"] = "boreal", + ["animalia:wolf"] = "boreal", +} + +----------- +-- Pages -- +----------- + + +local function get_spawn_biomes(name) + local biome_group = spawn_biomes[name] + local biomes = animalia.registered_biome_groups[biome_group].biomes + 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) + local def = minetest.registered_entities[name] + return def.textures or {unpack(def.male_textures), unpack(def.female_textures)} +end + +local biome_cubes = {} + +local function generate_page(mob) + local name = mob:split(":")[2] + local page = { + { -- Info + element_type = "label", + center_text = true, + font_size = 20, + offset = {x = 9, y = 1.5}, + file = "animalia_libri_" .. name .. ".txt" + }, + { -- Image + element_type = "model", + offset = {x = 1.5, y = 1.5}, + size = {x = 5, y = 5}, + texture_iter = 1, + text = "mesh;animalia_bat.b3d;" .. 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.5, 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} + } + }, + ["animalia:tropical_fish"] = { + { -- Info + element_type = "label", + center_text = true, + font_size = 20, + offset = {x = 9, y = 1.5}, + file = "animalia_libri_tropical_fish.txt" + }, + { -- Image + element_type = "model", + offset = {x = 1.5, y = 1.5}, + size = {x = 5, y = 5}, + texture_iter = 1, + models = { + "animalia_clownfish.b3d", + "animalia_clownfish.b3d", + "animalia_angelfish.b3d" + }, + text = "mesh;animalia_clownfish.b3d;" .. mob_textures("animalia:tropical_fish")[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("animalia:tropical_fish")[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("animalia:tropical_fish")[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("animalia:tropical_fish") / 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("animalia:tropical_fish") .. "_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("animalia:tropical_fish") .. "_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" + }) + } + } + 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 + form = form .. "style_type[label;font_size=" .. font_size .. "]" + if def.file then + local filename = path .. "/libri/" .. def.file + local file = io.open(filename) + if file then + local i = 0 + for line in file:lines() do + i = i + 1 + local center_offset = 0 + local max_length = (def.max_line or 48) + local line_length = line:len() + local total_line_area = font_size * line_length + local total_max_area = font_size * max_length + if def.center_text + and line_length < max_length then + center_offset = ((total_max_area - total_line_area) / 100) * 0.25 + end + local line_unit = (max_length * 0.075) + local align_x = (offset_x + line_unit - (line_unit * font_size_x)) + center_offset + local align_y = offset_y + (page_spacing * font_size_x) * i + form = form .. "label[" .. align_x .. "," .. align_y .. ";" .. color("#000000", line .. "\n") .. "]" + end + file:close() + end + else + 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 textures = mob_textures(page) + if textures[info.texture_iter + 1] then + info.texture_iter = info.texture_iter + 1 + else + info.texture_iter = 1 + end + local mesh = (info.models and info.models[info.texture_iter]) or minetest.registered_entities[page].mesh + info.text = "mesh;" .. mesh .. ";" .. textures[info.texture_iter] .. ";-30,225;false;false;0,0;0]" + end + if info.biome_iter then + local biome_group = spawn_biomes[page] + local registered_groups = animalia.registered_biome_groups + if registered_groups[biome_group].biomes[info.biome_iter + 1] then + info.biome_iter = info.biome_iter + 1 + else + info.biome_iter = 1 + end + local spawn_biome = registered_groups[biome_group].biomes[info.biome_iter] or "grassland" + if info.element_type == "image" then + info.text = biome_cubes[spawn_biome] + else + info.text = correct_string(spawn_biome) + 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, + 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] + 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) \ No newline at end of file diff --git a/api/spawning.lua b/api/spawning.lua index cdebc84..91b86a2 100644 --- a/api/spawning.lua +++ b/api/spawning.lua @@ -2,14 +2,6 @@ -- Spawning -- -------------- -local random = math.random - -local path = minetest.get_modpath("animalia") - -local storage = dofile(path .. "/api/storage.lua") - -animalia.spawn_points = storage.spawn_points - -- Get Biomes -- local chicken_biomes = {} @@ -44,6 +36,7 @@ creatura.register_mob_spawn("animalia:bat", { max_group = 5, biomes = animalia.registered_biome_groups["cave"].biomes, spawn_in_nodes = true, + spawn_on_gen = true, nodes = {"air", "ignore"} }) @@ -51,6 +44,7 @@ creatura.register_mob_spawn("animalia:chicken", { chance = 3, min_group = 3, max_group = 5, + spawn_on_gen = true, biomes = chicken_biomes }) @@ -58,6 +52,7 @@ creatura.register_mob_spawn("animalia:cow", { chance = 3, min_group = 3, max_group = 4, + spawn_on_gen = true, biomes = animalia.registered_biome_groups["grassland"].biomes }) @@ -73,6 +68,7 @@ creatura.register_mob_spawn("animalia:frog", { biomes = frog_biomes, spawn_cluster = true, spawn_in_nodes = true, + spawn_on_gen = true, nodes = {"default:water_source"}, }) @@ -80,6 +76,7 @@ creatura.register_mob_spawn("animalia:horse", { chance = 3, min_group = 4, max_group = 5, + spawn_on_gen = true, biomes = animalia.registered_biome_groups["grassland"].biomes }) @@ -87,6 +84,7 @@ creatura.register_mob_spawn("animalia:pig", { chance = 3, min_group = 2, max_group = 4, + spawn_on_gen = true, biomes = pig_biomes }) @@ -101,6 +99,7 @@ creatura.register_mob_spawn("animalia:sheep", { chance = 3, min_group = 3, max_group = 6, + spawn_on_gen = true, biomes = animalia.registered_biome_groups["grassland"].biomes }) @@ -108,6 +107,7 @@ creatura.register_mob_spawn("animalia:turkey", { chance = 2, min_group = 3, max_group = 4, + spawn_on_gen = true, biomes = animalia.registered_biome_groups["boreal"].biomes }) @@ -115,6 +115,7 @@ creatura.register_mob_spawn("animalia:wolf", { chance = 3, min_group = 2, max_group = 3, + spawn_on_gen = true, biomes = animalia.registered_biome_groups["boreal"].biomes }) @@ -157,194 +158,6 @@ creatura.register_mob_spawn("animalia:tropical_fish", { max_group = 12, spawn_cluster = true, spawn_in_nodes = true, + spawn_on_gen = true, nodes = {"default:water_source"} -}) - ---------------------- --- Mapgen Spawning -- ---------------------- - -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 - -local function get_biome_name(pos) - if not pos then return end - return minetest.get_biome_name(minetest.get_biome_data(pos).biome) -end - -local function dist_to_nearest_player(pos) - local dist - for _, player in pairs(minetest.get_connected_players()) do - local player_pos = player:get_pos() - if player_pos - and (not dist - or dist > vector.distance(pos, player_pos)) then - dist = vector.distance(pos, player_pos) - end - end - return dist or 100 -end - -local function get_spawnable_mobs(pos) - local biome = get_biome_name(pos) - if not biome then return end - local spawnable = {} - for k, v in pairs(creatura.registered_mob_spawns) do - if (not v.biomes - or is_value_in_table(v.biomes, biome)) - and k:match("^animalia:") - and not v.spawn_in_nodes then - table.insert(spawnable, k) - end - end - return spawnable -end - -local mapgen_spawning = minetest.settings:get_bool("animalia_mapgen_spawning") or true - -animalia.chunks_since_last_spawn = 0 - -local chunk_spawn_add_int = tonumber(minetest.settings:get("chunk_spawn_add_int")) or 6 - -animalia.spawn_queue = {} - -local c_air = minetest.get_content_id("air") - -minetest.register_on_generated(function(minp, maxp) - if not mapgen_spawning then return end - animalia.chunks_since_last_spawn = animalia.chunks_since_last_spawn + 1 - local max_y = maxp.y - local min_x = minp.x - local max_x = maxp.x - local min_z = minp.z - local max_z = maxp.z - - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local area = VoxelArea:new{MinEdge=emin, MaxEdge=emax} - local data = vm:get_data() - - local spawn_added = false - - for xcen = min_x + 8, max_x - 7, 8 do - if spawn_added then break end - for zcen = min_z + 8, max_z - 7, 8 do - local surface = false -- y of above surface node - for y = max_y, 2, -1 do - local vi = area:index(xcen, y, zcen) - local c_node = data[vi] - if not c_node then break end - local c_name = minetest.get_name_from_content_id(c_node) - local c_def = minetest.registered_nodes[c_name] - if y == max_y and c_node ~= c_air then -- if top node solid - break - elseif minetest.get_item_group(c_name, "leaves") > 0 then - break - elseif c_def.walkable then - surface = y + 1 - break - end - end - if animalia.chunks_since_last_spawn > chunk_spawn_add_int - and surface then - local center = { - x = xcen, - y = surface, - z = zcen, - } - local spawnable_mobs = get_spawnable_mobs(center) - if spawnable_mobs - and #spawnable_mobs > 0 then - local mob = spawnable_mobs[random(#spawnable_mobs)] - local spawn_def = creatura.registered_mob_spawns[mob] - table.insert(animalia.spawn_queue, - {pos = center, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)}) - table.insert(animalia.spawn_points, center) - end - spawn_added = true - animalia.chunks_since_last_spawn = 0 - end - end - end -end) - -local respawn_interval = 15 - -minetest.register_globalstep(function(dtime) - respawn_interval = respawn_interval - dtime - if respawn_interval <= 0 then - if #animalia.spawn_points > 0 then - for i = 1, #animalia.spawn_points do - local point = animalia.spawn_points[i] - if dist_to_nearest_player(point) < 48 - and minetest.get_node_or_nil(point) then - local spawnable_mobs = get_spawnable_mobs(point) - if spawnable_mobs - and #spawnable_mobs > 0 then - local mob = spawnable_mobs[random(#spawnable_mobs)] - local objects = minetest.get_objects_inside_radius(point, 32) - local spawn = true - if #objects > 0 then - for _, object in ipairs(objects) do - local ent = object and object:get_luaentity() - if ent - and ent.name:find("animalia:") then - spawn = false - break - end - end - end - if spawn then - local spawn_def = creatura.registered_mob_spawns[mob] - table.insert(animalia.spawn_queue, - {pos = point, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)}) - end - end - end - end - end - respawn_interval = 15 - end -end) - -local chunk_spawn_queue_int = tonumber(minetest.settings:get("chunk_spawn_queue_int")) or 16 - -local function spawn_queued() - if not mapgen_spawning then return end - local queue = animalia.spawn_queue - if #queue > 0 then - for i = #queue, 1, -1 do - if queue[i].mob then - local pos = queue[i].pos - if queue[i].group > 4 - or creatura.registered_mob_spawns[queue[i].mob].spawn_cluster then - pos = creatura.get_ground_level(pos, 4) - minetest.add_node(pos, {name = "creatura:spawn_node"}) - local meta = minetest.get_meta(pos) - meta:set_string("mob", queue[i].mob) - meta:set_string("cluster", queue[i].group) - else - for _ = 1, queue[i].group do - pos = { - x = pos.x + random(-3, 3), - y = pos.y, - z = pos.z + random(-3, 3) - } - pos = creatura.get_ground_level(pos, 4) - minetest.add_node(pos, {name = "creatura:spawn_node"}) - local meta = minetest.get_meta(pos) - meta:set_string("mob", queue[i].mob) - end - end - end - table.remove(animalia.spawn_queue, i) - end - end - minetest.after(chunk_spawn_queue_int, spawn_queued) -end -minetest.after(chunk_spawn_queue_int, spawn_queued) \ No newline at end of file +}) \ No newline at end of file diff --git a/api/storage.lua b/api/storage.lua index 802c948..efbec8a 100644 --- a/api/storage.lua +++ b/api/storage.lua @@ -1,19 +1,21 @@ local mod_storage = minetest.get_mod_storage() local data = { - spawn_points = minetest.deserialize(mod_storage:get_string("spawn_points")) or {}, + 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("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) + save() + minetest.after(120, periodic_save) end minetest.after(120, periodic_save) diff --git a/craftitems.lua b/craftitems.lua index ce0c597..28ee1a1 100644 --- a/craftitems.lua +++ b/craftitems.lua @@ -651,7 +651,7 @@ function animalia.show_libri_main_form(player, pages, group) minetest.show_formspec(player:get_player_name(), "animalia:libri_main", basic_form) end -minetest.register_craftitem("animalia:libri_animalia", { +--[[minetest.register_craftitem("animalia:libri_animalia", { description = "Libri Animalia", inventory_image = "animalia_libri_animalia.png", stack_max = 1, @@ -671,7 +671,7 @@ minetest.register_craftitem("animalia:libri_animalia", { or #pages < 1 then return end animalia.show_libri_main_form(player, pages) end -}) +})]] -------------- -- Crafting -- diff --git a/init.lua b/init.lua index a4d4049..9873ba5 100644 --- a/init.lua +++ b/init.lua @@ -1,5 +1,12 @@ 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 = {} minetest.register_on_joinplayer(function(player) @@ -24,8 +31,6 @@ end is_day() -local path = minetest.get_modpath("animalia") - dofile(path.."/api/api.lua") dofile(path.."/api/behaviors.lua") dofile(path.."/api/lasso.lua") @@ -56,6 +61,8 @@ 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 diff --git a/libri/animalia_libri_bat.txt b/libri/animalia_libri_bat.txt new file mode 100644 index 0000000..5c9eaff --- /dev/null +++ b/libri/animalia_libri_bat.txt @@ -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 \ No newline at end of file diff --git a/libri/animalia_libri_bird.txt b/libri/animalia_libri_bird.txt new file mode 100644 index 0000000..ffb138e --- /dev/null +++ b/libri/animalia_libri_bird.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_cat.txt b/libri/animalia_libri_cat.txt new file mode 100644 index 0000000..b83fbf3 --- /dev/null +++ b/libri/animalia_libri_cat.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_chicken.txt b/libri/animalia_libri_chicken.txt new file mode 100644 index 0000000..8153c95 --- /dev/null +++ b/libri/animalia_libri_chicken.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_cow.txt b/libri/animalia_libri_cow.txt new file mode 100644 index 0000000..9760771 --- /dev/null +++ b/libri/animalia_libri_cow.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_frog.txt b/libri/animalia_libri_frog.txt new file mode 100644 index 0000000..9a851c7 --- /dev/null +++ b/libri/animalia_libri_frog.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_home.txt b/libri/animalia_libri_home.txt new file mode 100644 index 0000000..da3ecbf --- /dev/null +++ b/libri/animalia_libri_home.txt @@ -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! \ No newline at end of file diff --git a/libri/animalia_libri_horse.txt b/libri/animalia_libri_horse.txt new file mode 100644 index 0000000..29cbe25 --- /dev/null +++ b/libri/animalia_libri_horse.txt @@ -0,0 +1,11 @@ +Horses are 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. \ No newline at end of file diff --git a/libri/animalia_libri_pig.txt b/libri/animalia_libri_pig.txt new file mode 100644 index 0000000..091a87b --- /dev/null +++ b/libri/animalia_libri_pig.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_reindeer.txt b/libri/animalia_libri_reindeer.txt new file mode 100644 index 0000000..091ef74 --- /dev/null +++ b/libri/animalia_libri_reindeer.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_sheep.txt b/libri/animalia_libri_sheep.txt new file mode 100644 index 0000000..9aed39b --- /dev/null +++ b/libri/animalia_libri_sheep.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_tropical_fish.txt b/libri/animalia_libri_tropical_fish.txt new file mode 100644 index 0000000..35bfe7c --- /dev/null +++ b/libri/animalia_libri_tropical_fish.txt @@ -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. diff --git a/libri/animalia_libri_turkey.txt b/libri/animalia_libri_turkey.txt new file mode 100644 index 0000000..ee87f4b --- /dev/null +++ b/libri/animalia_libri_turkey.txt @@ -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. \ No newline at end of file diff --git a/libri/animalia_libri_wolf.txt b/libri/animalia_libri_wolf.txt new file mode 100644 index 0000000..96ffb03 --- /dev/null +++ b/libri/animalia_libri_wolf.txt @@ -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. \ No newline at end of file diff --git a/mobs/bat.lua b/mobs/bat.lua index 4866ba0..77e54ba 100644 --- a/mobs/bat.lua +++ b/mobs/bat.lua @@ -24,7 +24,7 @@ local vec_dist = vector.distance local vec_add = vector.add local function vec_raise(v, n) - return {x = v.x, y = v.y + n, z = v.z} + return {x = v.x, y = v.y + n, z = v.z} end --------------- @@ -32,52 +32,52 @@ end --------------- local function get_roost(pos, range) - local walkable = minetest.find_nodes_in_area( - {x = pos.x + range, y = pos.y + range, z = pos.z + range}, - {x = pos.x - range, y = pos.y, z = pos.z - range}, - animalia.walkable_nodes - ) - if #walkable < 1 then return end - local roosts = {} - for i = 1, #walkable do - local i_pos = walkable[i] - local n_pos = { - x = i_pos.x, - y = i_pos.y - 1, - z = i_pos.z - } - if creatura.get_node_def(n_pos).name == "air" + local walkable = minetest.find_nodes_in_area( + {x = pos.x + range, y = pos.y + range, z = pos.z + range}, + {x = pos.x - range, y = pos.y, z = pos.z - range}, + animalia.walkable_nodes + ) + if #walkable < 1 then return end + local roosts = {} + for i = 1, #walkable do + local i_pos = walkable[i] + local n_pos = { + x = i_pos.x, + y = i_pos.y - 1, + z = i_pos.z + } + if creatura.get_node_def(n_pos).name == "air" and minetest.line_of_sight(pos, n_pos) then - table.insert(roosts, n_pos) - end - end - return roosts[random(#roosts)] + table.insert(roosts, n_pos) + end + end + return roosts[random(#roosts)] end local function is_node_walkable(name) - local def = minetest.registered_nodes[name] - return def and def.walkable + local def = minetest.registered_nodes[name] + return def and def.walkable end creatura.register_mob("animalia:bat", { - -- Stats - max_health = 5, - armor_groups = {fleshy = 200}, - damage = 0, - speed = 4, + -- Stats + max_health = 5, + armor_groups = {fleshy = 200}, + damage = 0, + speed = 4, tracking_range = 16, - despawn_after = 2500, + despawn_after = 2500, -- Entity Physics stepheight = 1.1, max_fall = 100, turn_rate = 12, - -- Visuals - mesh = "animalia_bat.b3d", - hitbox = { + -- Visuals + mesh = "animalia_bat.b3d", + hitbox = { width = 0.15, height = 0.3 }, - visual_size = {x = 7, y = 7}, + visual_size = {x = 7, y = 7}, textures = { "animalia_bat_1.png", "animalia_bat_2.png", @@ -86,27 +86,26 @@ creatura.register_mob("animalia:bat", { animations = { stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true}, walk = {range = {x = 50, y = 90}, speed = 30, frame_blend = 0.3, loop = true}, - fly = {range = {x = 100, y = 140}, speed = 80, frame_blend = 0.3, loop = true}, - cling = {range = {x = 150, y = 150}, speed = 1, frame_blend = 0, loop = false} + fly = {range = {x = 100, y = 140}, speed = 80, frame_blend = 0.3, loop = true}, + cling = {range = {x = 150, y = 150}, speed = 1, frame_blend = 0, loop = false} }, - -- Misc + -- Misc sounds = { random = { - name = "animalia_bat", - gain = 0.5, - distance = 16, + name = "animalia_bat", + gain = 0.5, + distance = 16, variations = 2 - }, - }, + }, + }, catch_with_net = true, catch_with_lasso = false, - follow = { + follow = { "butterflies:butterfly_red", "butterflies:butterfly_white", "butterflies:butterfly_violet" }, - -- Function - step_delay = 0.25, + -- Function roost_action = animalia.action_cling, utility_stack = { { @@ -165,7 +164,7 @@ creatura.register_mob("animalia:bat", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) self.home_position = self:recall("home_position") or nil @@ -177,8 +176,8 @@ creatura.register_mob("animalia:bat", { self.home_position = self:memorize("home_position", roost) end end - end, - step_func = function(self) + end, + step_func = function(self) animalia.step_timers(self) --animalia.head_tracking(self, 0.75, 0.75) animalia.do_growth(self, 60) @@ -245,12 +244,12 @@ creatura.register_mob("animalia:bat", { end end end - end, - death_func = function(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, false) then animalia.add_trust(self, clicker, 1) @@ -259,7 +258,6 @@ creatura.register_mob("animalia:bat", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "bat", form = "pg_bat;Bats"}) 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) diff --git a/mobs/bird.lua b/mobs/bird.lua index e937c2b..187b8e8 100644 --- a/mobs/bird.lua +++ b/mobs/bird.lua @@ -48,7 +48,7 @@ creatura.register_mob("animalia:bird", { fly = {range = {x = 120, y = 140}, speed = 80, frame_blend = 0.3, loop = true} }, -- Misc - step_delay = 0.25, + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = false, sounds = { @@ -212,7 +212,6 @@ creatura.register_mob("animalia:bird", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "bird", form = "pg_bird;Birds"}) 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) diff --git a/mobs/cat.lua b/mobs/cat.lua index 2737f27..f9779d4 100644 --- a/mobs/cat.lua +++ b/mobs/cat.lua @@ -18,18 +18,18 @@ if minetest.registered_items["ethereal:fish_raw"] then end creatura.register_mob("animalia:cat", { - -- Stats - max_health = 10, - armor_groups = {fleshy = 200}, - damage = 1, - speed = 5, + -- Stats + max_health = 10, + armor_groups = {fleshy = 200}, + damage = 1, + speed = 5, tracking_range = 24, turn_rate = 9, - despawn_after = 2000, + despawn_after = 2000, -- Entity Physics stepheight = 1.1, - -- Visuals - mesh = "animalia_cat.b3d", + -- Visuals + mesh = "animalia_cat.b3d", hitbox = { width = 0.2, height = 0.4 @@ -56,41 +56,41 @@ creatura.register_mob("animalia:cat", { sit = {range = {x = 81, y = 99}, speed = 10, frame_blend = 0.3, loop = true}, smack = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.1, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, sounds = { - random = { - name = "animalia_cat_idle", - gain = 0.25, - distance = 8 - }, + random = { + name = "animalia_cat_idle", + 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 - } + 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 + } }, - follow = follow, + follow = follow, head_data = { offset = {x = 0, y = 0.18, z = 0}, pitch_correction = -20, pivot_h = 0.65, pivot_v = 0.65 }, - -- Function - activate_func = function(self) + -- Function + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) self.interact_sound_cooldown = 0 @@ -104,7 +104,7 @@ creatura.register_mob("animalia:cat", { table.insert(animalia.pets[self.owner], self.object) end end - end, + end, utility_stack = { { utility = "animalia:wander_skittish", @@ -203,22 +203,23 @@ creatura.register_mob("animalia:cat", { end } }, - step_func = function(self) + 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 = function(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) local item_name = clicker:get_wielded_item():get_name() if item_name == "animalia:net" then return end @@ -252,7 +253,6 @@ creatura.register_mob("animalia:cat", { self:play_sound("purr") end end - animalia.add_libri_page(self, clicker, {name = "cat", form = "pg_cat;Cats"}) if not self.owner or clicker:get_player_name() ~= self.owner then return diff --git a/mobs/chicken.lua b/mobs/chicken.lua index 2a23b26..bd0af38 100644 --- a/mobs/chicken.lua +++ b/mobs/chicken.lua @@ -5,33 +5,33 @@ local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if name:match(":seed_") + for name in pairs(minetest.registered_items) do + if name:match(":seed_") or name:match("_seed") then table.insert(follows, name) - end - end + end + end end) creatura.register_mob("animalia:chicken", { - -- Stats - max_health = 5, - armor_groups = {fleshy = 150}, - damage = 0, - speed = 4, + -- Stats + max_health = 5, + armor_groups = {fleshy = 150}, + damage = 0, + speed = 4, tracking_range = 4, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, max_fall = 8, turn_rate = 7, - -- Visuals - mesh = "animalia_chicken.b3d", + -- Visuals + mesh = "animalia_chicken.b3d", hitbox = { width = 0.15, height = 0.3 }, - visual_size = {x = 7, y = 7}, + visual_size = {x = 7, y = 7}, female_textures = { "animalia_chicken_1.png", "animalia_chicken_2.png", @@ -43,45 +43,48 @@ creatura.register_mob("animalia:chicken", { "animalia_rooster_3.png" }, child_textures = {"animalia_chicken_child.png"}, - animations = { + 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} + fall = {range = {x = 91, y = 99}, speed = 70, frame_blend = 0.3, loop = true} }, - -- Misc + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, - sounds = { - random = { - name = "animalia_chicken_idle", - 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 - } - }, - drops = { - {name = "animalia:poultry_raw", min = 1, max = 3, chance = 1}, + sounds = { + random = { + name = "animalia_chicken_idle", + 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 + } + }, + drops = { + {name = "animalia:poultry_raw", min = 1, max = 3, chance = 1}, {name = "animalia:feather", min = 1, max = 3, chance = 2} - }, - follow = follows, + }, + follow = follows, head_data = { offset = {x = 0, y = 0.45, z = 0}, pitch_correction = 40, pivot_h = 0.25, pivot_v = 0.55 }, - -- Function + move_chance = 2, + idle_time = 1, + -- Function add_child = function(self) local pos = self.object:get_pos() if not pos then return end @@ -158,28 +161,31 @@ creatura.register_mob("animalia:chicken", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) - end, - step_func = function(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:timer(60) then - animalia.random_drop_item(self, "animalia:chicken_egg", 3) + 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) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -187,7 +193,6 @@ creatura.register_mob("animalia:chicken", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "chicken", form = "pg_chicken;Chickens"}) 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) diff --git a/mobs/cow.lua b/mobs/cow.lua index eabdcac..2987248 100644 --- a/mobs/cow.lua +++ b/mobs/cow.lua @@ -7,33 +7,34 @@ local random = math.random local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if (name:match(":wheat") + for name in pairs(minetest.registered_items) do + if (name:match(":wheat") or minetest.get_item_group(name, "food_wheat") > 0) + and not tonumber(name:sub(-1)) and not name:find("seed") then table.insert(follows, name) - end - end + end + end end) creatura.register_mob("animalia:cow", { - -- Stats - max_health = 20, - armor_groups = {fleshy = 150}, - damage = 0, - speed = 3, + -- Stats + max_health = 20, + armor_groups = {fleshy = 150}, + damage = 0, + speed = 3, tracking_range = 16, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, turn_rate = 6, - -- Visuals - mesh = "animalia_cow.b3d", + -- Visuals + mesh = "animalia_cow.b3d", hitbox = { width = 0.65, height = 1.5 }, - visual_size = {x = 10, y = 10}, + visual_size = {x = 10, y = 10}, female_textures = { "animalia_cow_1.png^animalia_cow_udder.png", "animalia_cow_2.png^animalia_cow_udder.png", @@ -57,33 +58,32 @@ creatura.register_mob("animalia:cow", { walk = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true}, run = {range = {x = 61, y = 79}, speed = 30, frame_blend = 0.3, loop = true}, }, - -- Misc + -- Misc step_delay = 0.25, catch_with_net = true, catch_with_lasso = true, sounds = { - random = { - name = "animalia_cow_random", - gain = 0.4, - distance = 8, - variations = 3 - }, - hurt = { - name = "animalia_cow_hurt", - gain = 0.4, - distance = 8 - }, - death = { - name = "animalia_cow_death", - gain = 0.4, - distance = 8 - } - }, - drops = { - {name = "animalia:beef_raw", min = 1, max = 3, chance = 1}, + random = { + name = "animalia_cow_random", + gain = 0.4, + distance = 8 + }, + hurt = { + name = "animalia_cow_hurt", + gain = 0.4, + distance = 8 + }, + death = { + name = "animalia_cow_death", + gain = 0.4, + distance = 8 + } + }, + drops = { + {name = "animalia:beef_raw", min = 1, max = 3, chance = 1}, {name = "animalia:leather", min = 1, max = 3, chance = 2} - }, - follow = follows, + }, + follow = follows, consumable_nodes = { ["default:dirt_with_grass"] = "default:dirt", ["default:dry_dirt_with_dry_grass"] = "default:dry_dirt" @@ -94,7 +94,7 @@ creatura.register_mob("animalia:cow", { pivot_h = 0.75, pivot_v = 1 }, - -- Function + -- Function utility_stack = { { utility = "animalia:wander", @@ -160,22 +160,23 @@ creatura.register_mob("animalia:cow", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) - self.collected = self:recall("collected") or false - end, - step_func = function(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) - end, - death_func = function(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, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -213,7 +214,6 @@ creatura.register_mob("animalia:cow", { self.collected = self:memorize("collected", true) return end - animalia.add_libri_page(self, clicker, {name = "cow", form = "pg_cow;Cows"}) 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) diff --git a/mobs/frog.lua b/mobs/frog.lua index f1fc61e..d6f1d10 100644 --- a/mobs/frog.lua +++ b/mobs/frog.lua @@ -9,26 +9,26 @@ local vec_dist = vector.distance local vec_sub = vector.subtract creatura.register_mob("animalia:frog", { - -- Stats - max_health = 5, - armor_groups = {fleshy = 200}, - damage = 0, - speed = 4, + -- Stats + max_health = 5, + armor_groups = {fleshy = 200}, + damage = 0, + speed = 4, tracking_range = 16, - despawn_after = 2500, + despawn_after = 2500, -- Entity Physics stepheight = 1.1, max_fall = 0, turn_rate = 10, bouyancy_multiplier = 0, hydrodynamics_multiplier = 0.3, - -- Visuals - mesh = "animalia_frog.b3d", - hitbox = { + -- Visuals + mesh = "animalia_frog.b3d", + hitbox = { width = 0.15, height = 0.3 }, - visual_size = {x = 7, y = 7}, + visual_size = {x = 7, y = 7}, textures = { "animalia_frog_1.png", "animalia_frog_2.png" @@ -43,20 +43,19 @@ creatura.register_mob("animalia:frog", { 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} }, - -- Misc - step_delay = 0.25, + -- Misc makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, sounds = { random = { - name = "animalia_frog", - gain = 0.5, - distance = 32, + name = "animalia_frog", + gain = 0.5, + distance = 32, variations = 3 - } - }, - follow = { + } + }, + follow = { "butterflies:butterfly_red", "butterflies:butterfly_white", "butterflies:butterfly_violet" @@ -67,7 +66,7 @@ creatura.register_mob("animalia:frog", { pivot_h = 0.3, pivot_v = 0.3 }, - -- Function + -- Function utility_stack = { { utility = "animalia:wander", @@ -159,7 +158,7 @@ creatura.register_mob("animalia:frog", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) self.trust = self:recall("trust") or {} @@ -168,13 +167,13 @@ creatura.register_mob("animalia:frog", { local anim = {range = {x = frame, y = frame}, speed = 1, frame_blend = 0.3, loop = false} self.animations["tongue_" .. i] = anim end - end, - step_func = function(self) + end, + step_func = function(self) animalia.step_timers(self) animalia.head_tracking(self, 0.2, 0.2) animalia.do_growth(self, 60) animalia.update_lasso_effects(self) - if self:timer(random(5, 10)) then + if self:timer(random(5, 15)) then self:play_sound("random") end local props = self.object:get_properties() @@ -184,12 +183,12 @@ creatura.register_mob("animalia:frog", { mesh = "animalia_tadpole.b3d" }) end - end, - death_func = function(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then animalia.add_trust(self, clicker, 1) @@ -198,7 +197,6 @@ creatura.register_mob("animalia:frog", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "frog", form = "pg_frog;Frogs"}) 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) diff --git a/mobs/horse.lua b/mobs/horse.lua index 98f02bd..a4e56eb 100644 --- a/mobs/horse.lua +++ b/mobs/horse.lua @@ -7,13 +7,13 @@ local random = math.random local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if (name:match(":wheat") + 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(follows, name) - end - end + end + end end) local patterns = { @@ -72,24 +72,24 @@ local function set_pattern(self) end creatura.register_mob("animalia:horse", { - -- Stats - max_health = 40, - armor_groups = {fleshy = 100}, - damage = 0, - speed = 10, + -- Stats + max_health = 40, + armor_groups = {fleshy = 100}, + damage = 0, + speed = 10, tracking_range = 24, - despawn_after = 2000, + despawn_after = 2000, -- Entity Physics stepheight = 1.1, - turn_rate = 6, + turn_rate = 8, boid_seperation = 1.5, - -- Visuals - mesh = "animalia_horse.b3d", + -- Visuals + mesh = "animalia_horse.b3d", hitbox = { width = 0.65, height = 1.95 }, - visual_size = {x = 10, y = 10}, + visual_size = {x = 10, y = 10}, textures = { "animalia_horse_1.png", "animalia_horse_2.png", @@ -107,33 +107,33 @@ creatura.register_mob("animalia:horse", { rear_constant = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.3, loop = false}, eat = {range = {x = 141, y = 160}, speed = 20, frame_blend = 0.3, loop = false} }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, - sounds = { - alter_child_pitch = true, - random = { + sounds = { + alter_child_pitch = true, + random = { name = "animalia_horse_idle", gain = 1.0, distance = 8, variations = 3, }, - hurt = { - name = "animalia_horse_hurt", - gain = 1.0, - distance = 8 - }, - death = { - name = "animalia_horse_death", - gain = 1.0, - distance = 8 - } - }, - drops = { + hurt = { + name = "animalia_horse_hurt", + gain = 1.0, + distance = 8 + }, + death = { + name = "animalia_horse_death", + gain = 1.0, + distance = 8 + } + }, + drops = { {name = "animalia:leather", min = 1, max = 4, chance = 2} - }, - follow = follows, + }, + follow = follows, consumable_nodes = { ["default:dirt_with_grass"] = "default:dirt", ["default:dry_dirt_with_dry_grass"] = "default:dry_dirt" @@ -145,7 +145,30 @@ creatura.register_mob("animalia:horse", { pivot_h = 1, pivot_v = 1.5 }, - -- Function + -- Function + 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 not mate_ent 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, wander_action = animalia.action_move_flock, utility_stack = { { @@ -235,7 +258,7 @@ creatura.register_mob("animalia:horse", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) set_pattern(self) @@ -262,18 +285,19 @@ creatura.register_mob("animalia:horse", { {name = "animalia:saddle", chance = 1, min = 1, max = 1} } end - end, - step_func = function(self) + 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) + animalia.random_sound(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -284,7 +308,7 @@ creatura.register_mob("animalia:horse", { local tool = clicker:get_wielded_item() local tool_name = clicker:get_wielded_item():get_name() if self.owner - and self.owner == clicker:get_player_name() then + and self.owner == clicker:get_player_name() then if self.saddled and tool_name == "" then animalia.mount(self, clicker, {rot = {x = -75, y = 180, z = 0}, pos = {x = 0, y = 0.6, z = 0.5}}) @@ -302,11 +326,10 @@ creatura.register_mob("animalia:horse", { tool:take_item() clicker:set_wielded_item(tool) end - elseif not self.owner + elseif not self.owner and tool_name == "" then - animalia.mount(self, clicker, {rot = {x = -60, y = 180, z = 0}, pos = {x = 0, y = 1.1, z = 0.5}}) + animalia.mount(self, clicker, {rot = {x = -75, y = 180, z = 0}, pos = {x = 0, y = 0.6, z = 0.5}}) end - animalia.add_libri_page(self, clicker, {name = "horse", form = "pg_horse;Horses"}) end, on_punch = function(self, puncher, ...) if self.rider and puncher == self.rider then return end diff --git a/mobs/pig.lua b/mobs/pig.lua index 7429d8d..5f31a6e 100644 --- a/mobs/pig.lua +++ b/mobs/pig.lua @@ -5,13 +5,13 @@ local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if name:match(":carrot") + for name in pairs(minetest.registered_items) do + if name:match(":carrot") and (minetest.get_item_group(name, "food") > 0 or minetest.get_item_group(name, "food_carrot") > 0) then table.insert(follows, name) - end - end + end + end end) local destroyable_crops = {} @@ -26,18 +26,18 @@ minetest.register_on_mods_loaded(function() end) creatura.register_mob("animalia:pig", { - -- Stats - max_health = 10, - armor_groups = {fleshy = 100}, - damage = 0, - speed = 3, + -- Stats + max_health = 10, + armor_groups = {fleshy = 100}, + damage = 0, + speed = 3, tracking_range = 16, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, turn_rate = 6, - -- Visuals - mesh = "animalia_pig.b3d", + -- Visuals + mesh = "animalia_pig.b3d", hitbox = { width = 0.35, height = 0.7 @@ -63,34 +63,34 @@ creatura.register_mob("animalia:pig", { walk = {range = {x = 1, y = 20}, speed = 30, frame_blend = 0.3, loop = true}, run = {range = {x = 1, y = 20}, speed = 45, frame_blend = 0.3, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, consumable_nodes = destroyable_crops, birth_count = 2, catch_with_net = true, catch_with_lasso = true, sounds = { - random = { - name = "animalia_pig_idle", - gain = 1.0, - distance = 8 - }, - hurt = { - name = "animalia_pig_hurt", + random = { + name = "animalia_pig_idle", gain = 1.0, - distance = 8 - }, - death = { - name = "animalia_pig_death", + distance = 8 + }, + hurt = { + name = "animalia_pig_hurt", gain = 1.0, - distance = 8 - } - }, - drops = { - {name = "animalia:porkchop_raw", min = 1, max = 3, chance = 1} - }, - follow = follows, - -- Function + distance = 8 + }, + death = { + name = "animalia_pig_death", + gain = 1.0, + distance = 8 + } + }, + drops = { + {name = "animalia:porkchop_raw", min = 1, max = 3, chance = 1} + }, + follow = follows, + -- Function utility_stack = { [1] = { utility = "animalia:wander", @@ -144,20 +144,21 @@ creatura.register_mob("animalia:pig", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) - end, - step_func = function(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) + animalia.random_sound(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -165,7 +166,6 @@ creatura.register_mob("animalia:pig", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "pig", form = "pg_pig;Pigs"}) 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) diff --git a/mobs/reindeer.lua b/mobs/reindeer.lua index b0caa22..95525dd 100644 --- a/mobs/reindeer.lua +++ b/mobs/reindeer.lua @@ -5,36 +5,36 @@ local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if (name:match(":wheat") + 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(follows, name) - end - end + end + end end) local random = math.random creatura.register_mob("animalia:reindeer", { - -- Stats - max_health = 20, - armor_groups = {fleshy = 125}, - damage = 0, - speed = 3, + -- Stats + max_health = 20, + armor_groups = {fleshy = 125}, + damage = 0, + speed = 3, boid_seperation = 1, tracking_range = 16, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, turn_rate = 4, - -- Visuals - mesh = "animalia_reindeer.b3d", + -- Visuals + mesh = "animalia_reindeer.b3d", hitbox = { width = 0.45, height = 0.9 }, - visual_size = {x = 10, y = 10}, + visual_size = {x = 10, y = 10}, textures = {"animalia_reindeer.png"}, child_textures = {"animalia_reindeer_calf.png"}, animations = { @@ -42,15 +42,15 @@ creatura.register_mob("animalia:reindeer", { walk = {range = {x = 70, y = 110}, speed = 40, frame_blend = 0.3, loop = true}, run = {range = {x = 70, y = 110}, speed = 50, frame_blend = 0.3, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, - drops = { - {name = "animalia:venison_raw", min = 1, max = 3, chance = 1}, + drops = { + {name = "animalia:venison_raw", min = 1, max = 3, chance = 1}, {name = "animalia:leather", min = 1, max = 3, chance = 2} - }, - follow = follows, + }, + follow = follows, consumable_nodes = { { name = "default:dirt_with_grass", @@ -67,7 +67,9 @@ creatura.register_mob("animalia:reindeer", { pivot_h = 1, pivot_v = 1 }, - -- Function + move_chance = 2, + idle_time = 1, + -- Function utility_stack = { { utility = "animalia:wander_group", @@ -133,21 +135,21 @@ creatura.register_mob("animalia:reindeer", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) - end, - step_func = function(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) - end, - death_func = function(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -155,7 +157,6 @@ creatura.register_mob("animalia:reindeer", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "reindeer", form = "pg_reindeer;Reindeer"}) 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) diff --git a/mobs/sheep.lua b/mobs/sheep.lua index 67ae3bd..94ea92c 100644 --- a/mobs/sheep.lua +++ b/mobs/sheep.lua @@ -7,13 +7,13 @@ local random = math.random local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if (name:match(":wheat") + 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(follows, name) - end - end + end + end end) local wool_block = "wool:white" @@ -43,17 +43,17 @@ local palette = { } creatura.register_mob("animalia:sheep", { - -- Stats - max_health = 15, - armor_groups = {fleshy = 125}, - damage = 0, - speed = 3, + -- Stats + max_health = 15, + armor_groups = {fleshy = 125}, + damage = 0, + speed = 3, tracking_range = 16, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, - -- Visuals - mesh = "animalia_sheep.b3d", + -- Visuals + mesh = "animalia_sheep.b3d", hitbox = { width = 0.4, height = 0.8 @@ -70,32 +70,32 @@ creatura.register_mob("animalia:sheep", { walk = {range = {x = 70, y = 110}, speed = 40, frame_blend = 0.3, loop = true}, run = {range = {x = 70, y = 110}, speed = 50, frame_blend = 0.3, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, sounds = { - random = { - name = "animalia_sheep_idle", - gain = 1.0, - distance = 8 - }, - hurt = { - name = "animalia_sheep_hurt", + random = { + name = "animalia_sheep_idle", gain = 1.0, - distance = 8 - }, - death = { - name = "animalia_sheep_death", + distance = 8 + }, + hurt = { + name = "animalia_sheep_hurt", gain = 1.0, - distance = 8 - } - }, - drops = { - {name = "animalia:mutton_raw", min = 1, max = 3, chance = 1}, + distance = 8 + }, + death = { + name = "animalia_sheep_death", + gain = 1.0, + distance = 8 + } + }, + drops = { + {name = "animalia:mutton_raw", min = 1, max = 3, chance = 1}, {name = wool_block, min = 1, max = 3, chance = 2} - }, - follow = follows, + }, + follow = follows, consumable_nodes = { ["default:dirt_with_grass"] = "default:dirt", ["default:dry_dirt_with_dry_grass"] = "default:dry_dirt" @@ -106,7 +106,7 @@ creatura.register_mob("animalia:sheep", { pivot_h = 0.75, pivot_v = 0.85 }, - -- Function + -- Function utility_stack = { { utility = "animalia:wander_group", @@ -174,8 +174,8 @@ creatura.register_mob("animalia:sheep", { end } }, - activate_func = function(self) - self.collected = self:recall("collected") or false + activate_func = function(self) + self.collected = self:recall("collected") or false self.dye_color = self:recall("dye_color") or "white" self.dye_hex = self:recall("dye_hex") or "" if self.dye_color ~= "white" @@ -189,22 +189,23 @@ creatura.register_mob("animalia:sheep", { textures = {"animalia_sheep.png"}, }) end - self.attention_span = 8 - self._path = {} + self.attention_span = 8 + self._path = {} animalia.initialize_api(self) animalia.initialize_lasso(self) - end, - step_func = function(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) - end, - death_func = function(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, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -265,7 +266,6 @@ creatura.register_mob("animalia:sheep", { end end end - animalia.add_libri_page(self, clicker, {name = "sheep", form = "pg_sheep;Sheep"}) 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) diff --git a/mobs/tropical_fish.lua b/mobs/tropical_fish.lua index bc28b98..4004615 100644 --- a/mobs/tropical_fish.lua +++ b/mobs/tropical_fish.lua @@ -3,41 +3,41 @@ ---------- creatura.register_mob("animalia:tropical_fish", { - -- Stats - max_health = 5, - armor_groups = {fleshy = 150}, - damage = 0, - speed = 2, + -- Stats + max_health = 5, + armor_groups = {fleshy = 150}, + damage = 0, + speed = 2, tracking_range = 6, - despawn_after = 2500, + despawn_after = 2500, -- Entity Physics stepheight = 0.1, max_fall = 0, turn_rate = 8, boid_seperation = 0.3, bouyancy_multiplier = 0, - -- Visuals - mesh = "animalia_clownfish.b3d", + -- Visuals + mesh = "animalia_clownfish.b3d", hitbox = { width = 0.15, height = 0.3 }, - visual_size = {x = 7, y = 7}, + visual_size = {x = 7, y = 7}, textures = { "animalia_clownfish.png", "animalia_blue_tang.png", "animalia_angelfish.png" }, - animations = { + 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}, }, - -- Misc + -- Misc step_delay = 0.25, catch_with_net = true, catch_with_lasso = false, makes_footstep_sound = false, - -- Function + -- Function utility_stack = { { utility = "animalia:aquatic_wander_school", @@ -58,7 +58,7 @@ creatura.register_mob("animalia:tropical_fish", { end }, }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) if self.texture_no == 3 then @@ -66,22 +66,21 @@ creatura.register_mob("animalia:tropical_fish", { mesh = "animalia_angelfish.b3d", }) end - end, - step_func = function(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) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "tropical_fish", form = "pg_tropical_fish;Tropical Fish"}) 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) diff --git a/mobs/turkey.lua b/mobs/turkey.lua index c62a226..79df55e 100644 --- a/mobs/turkey.lua +++ b/mobs/turkey.lua @@ -5,74 +5,76 @@ local follows = {} minetest.register_on_mods_loaded(function() - for name in pairs(minetest.registered_items) do - if name:match(":seed_") + for name in pairs(minetest.registered_items) do + if name:match(":seed_") or name:match("_seed") then table.insert(follows, name) - end - end + end + end end) creatura.register_mob("animalia:turkey", { - -- Stats - max_health = 10, - armor_groups = {fleshy = 150}, - damage = 0, - speed = 4, + -- Stats + max_health = 10, + armor_groups = {fleshy = 150}, + damage = 0, + speed = 4, tracking_range = 16, - despawn_after = 1500, + despawn_after = 1500, -- Entity Physics stepheight = 1.1, max_fall = 8, - -- Visuals - mesh = "animalia_turkey.b3d", + -- Visuals + mesh = "animalia_turkey.b3d", hitbox = { width = 0.3, height = 0.6 }, - visual_size = {x = 7, y = 7}, + visual_size = {x = 7, y = 7}, female_textures = {"animalia_turkey_hen.png"}, male_textures = {"animalia_turkey_tom.png"}, child_textures = {"animalia_turkey_chick.png"}, - animations = { + 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}, + fall = {range = {x = 70, y = 90}, speed = 30, frame_blend = 0.3, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, - sounds = { - random = { - name = "animalia_turkey_idle", - gain = 1.0, - distance = 8 - }, - hurt = { - name = "animalia_turkey_hurt", - gain = 1.0, - distance = 8 - }, - death = { - name = "animalia_turkey_death", - gain = 1.0, - distance = 8 - } - }, - drops = { - {name = "animalia:poultry_raw", min = 2, max = 4, chance = 1}, + sounds = { + random = { + name = "animalia_turkey_idle", + gain = 1.0, + distance = 8 + }, + hurt = { + name = "animalia_turkey_hurt", + gain = 1.0, + distance = 8 + }, + death = { + name = "animalia_turkey_death", + gain = 1.0, + distance = 8 + } + }, + drops = { + {name = "animalia:poultry_raw", min = 2, max = 4, chance = 1}, {name = "animalia:feather", min = 2, max = 4, chance = 2} - }, - follow = follows, + }, + follow = follows, head_data = { offset = {x = 0, y = 0.15, z = 0}, pitch_correction = 45, pivot_h = 0.45, pivot_v = 0.65 }, - -- Function + move_chance = 2, + idle_time = 1, + -- Function add_child = function(self) local pos = self.object:get_pos() if not pos then return end @@ -147,28 +149,31 @@ creatura.register_mob("animalia:turkey", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) - end, - step_func = function(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:timer(60) then - animalia.random_drop_item(self, "animalia:chicken_egg", 3) + 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) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if animalia.feed(self, clicker, false, true) then return @@ -176,7 +181,6 @@ creatura.register_mob("animalia:turkey", { if animalia.set_nametag(self, clicker) then return end - animalia.add_libri_page(self, clicker, {name = "turkey", form = "pg_turkey;Turkeys"}) 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) diff --git a/mobs/wolf.lua b/mobs/wolf.lua index 3ace9c6..fa3d353 100644 --- a/mobs/wolf.lua +++ b/mobs/wolf.lua @@ -35,32 +35,32 @@ if minetest.registered_items["bonemeal:bone"] then 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 + for _, v in pairs(tbl) do + if v == val then + return true + end + end + return false end creatura.register_mob("animalia:wolf", { - -- Stats - max_health = 15, - armor_groups = {fleshy = 100}, - damage = 4, - speed = 5, + -- Stats + max_health = 15, + armor_groups = {fleshy = 100}, + damage = 4, + speed = 5, tracking_range = 24, - despawn_after = 2000, + despawn_after = 2000, -- Entity Physics stepheight = 1.1, max_fall = 3, - -- Visuals - mesh = "animalia_wolf.b3d", + -- Visuals + mesh = "animalia_wolf.b3d", hitbox = { width = 0.35, height = 0.7 }, - visual_size = {x = 9, y = 9}, + visual_size = {x = 9, y = 9}, textures = { "animalia_wolf_1.png", "animalia_wolf_2.png", @@ -73,19 +73,19 @@ creatura.register_mob("animalia:wolf", { run = {range = {x = 41, y = 59}, speed = 45, frame_blend = 0.3, loop = true}, sit = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true}, }, - -- Misc - step_delay = 0.25, + -- Misc + makes_footstep_sound = true, catch_with_net = true, catch_with_lasso = true, assist_owner = true, - follow = follow, + follow = follow, head_data = { offset = {x = 0, y = 0.33, z = 0}, pitch_correction = -67, pivot_h = 0.65, pivot_v = 0.65 }, - -- Function + -- Function utility_stack = { { utility = "animalia:wander_skittish", @@ -155,7 +155,7 @@ creatura.register_mob("animalia:wolf", { end } }, - activate_func = function(self) + activate_func = function(self) animalia.initialize_api(self) animalia.initialize_lasso(self) self.order = self:recall("order") or "wander" @@ -167,18 +167,18 @@ creatura.register_mob("animalia:wolf", { table.insert(animalia.pets[self.owner], self.object) end end - end, - step_func = function(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 = function(self) + end, + death_func = function(self) if self:get_utility() ~= "animalia:die" then self:initiate_utility("animalia:die", self) end - end, + end, on_rightclick = function(self, clicker) if not clicker:is_player() then return end local name = clicker:get_player_name() @@ -211,7 +211,6 @@ creatura.register_mob("animalia:wolf", { end self:memorize("order", self.order) end - animalia.add_libri_page(self, clicker, {name = "wolf", form = "pg_wolf;Wolves"}) 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) diff --git a/sounds/cow/animalia_cow_death.ogg b/sounds/cow/animalia_cow_death.ogg index 10b278e..05b2e3d 100644 Binary files a/sounds/cow/animalia_cow_death.ogg and b/sounds/cow/animalia_cow_death.ogg differ diff --git a/sounds/cow/animalia_cow_hurt.ogg b/sounds/cow/animalia_cow_hurt.ogg index aa1fa42..a5110c9 100644 Binary files a/sounds/cow/animalia_cow_hurt.ogg and b/sounds/cow/animalia_cow_hurt.ogg differ diff --git a/sounds/cow/animalia_cow_idle.ogg b/sounds/cow/animalia_cow_idle.ogg deleted file mode 100644 index 905b0ca..0000000 Binary files a/sounds/cow/animalia_cow_idle.ogg and /dev/null differ diff --git a/sounds/cow/animalia_cow_random.ogg b/sounds/cow/animalia_cow_random.ogg new file mode 100644 index 0000000..cb89033 Binary files /dev/null and b/sounds/cow/animalia_cow_random.ogg differ diff --git a/sounds/cow/animalia_cow_random_1.ogg b/sounds/cow/animalia_cow_random_1.ogg deleted file mode 100644 index bfa5100..0000000 Binary files a/sounds/cow/animalia_cow_random_1.ogg and /dev/null differ diff --git a/sounds/cow/animalia_cow_random_2.ogg b/sounds/cow/animalia_cow_random_2.ogg deleted file mode 100644 index a9dc253..0000000 Binary files a/sounds/cow/animalia_cow_random_2.ogg and /dev/null differ diff --git a/sounds/cow/animalia_cow_random_3.ogg b/sounds/cow/animalia_cow_random_3.ogg deleted file mode 100644 index 4ae604a..0000000 Binary files a/sounds/cow/animalia_cow_random_3.ogg and /dev/null differ diff --git a/textures/formspecs/libri/animalia_libri_bg.png b/textures/formspecs/libri/animalia_libri_bg.png index bcbd615..1e11672 100644 Binary files a/textures/formspecs/libri/animalia_libri_bg.png and b/textures/formspecs/libri/animalia_libri_bg.png differ diff --git a/textures/formspecs/libri/icons/animalia_libri_icon_last.png b/textures/formspecs/libri/icons/animalia_libri_icon_last.png new file mode 100644 index 0000000..28a4d36 Binary files /dev/null and b/textures/formspecs/libri/icons/animalia_libri_icon_last.png differ diff --git a/textures/formspecs/libri/icons/animalia_libri_icon_next.png b/textures/formspecs/libri/icons/animalia_libri_icon_next.png new file mode 100644 index 0000000..e601c43 Binary files /dev/null and b/textures/formspecs/libri/icons/animalia_libri_icon_next.png differ