master
root 2021-01-10 00:36:51 +01:00
parent afb3fc6fc0
commit 7db010d3b5
197 changed files with 3959 additions and 5578 deletions

View File

@ -299,6 +299,7 @@ for i = 1, #aquaz.coral_deco do
paramtype = "light",
paramtype2 = "facedir",
tiles = {aquaz.coral_deco[i].tile},
use_texture_alpha = true,
inventory_image = aquaz.coral_deco[i].tile,
wield_image = aquaz.coral_deco[i].tile,
node_box = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -248,6 +248,7 @@ end)
function closet.register_container(name, d)
local def = table.copy(d)
def.drawtype = 'mesh'
def.use_texture_alpha = true
def.paramtype = "light"
def.paramtype2 = "facedir"
def.is_ground_content = false

View File

@ -7,6 +7,7 @@ closet.register_container("closet", {
tiles = {
"closet_closet.png",
},
use_texture_alpha = true,
selection_box = {
type = "fixed",
fixed = { -1/2, -1/2, 0.062500, 1/2, 1.5, 1/2 },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,8 @@
# Blossom Hedges
Beautiful hedges made from flowers
## Licenses
- Code: GPL v3.0
- Textures: CC BY-SA 4.0

View File

@ -0,0 +1,69 @@
-- Blossom Hedges
local S = minetest.get_translator(minetest.get_current_modname())
local hedges = {
{
"white_blue",
S("White & Blue"),
{"flowers:dandelion_white", "flowers:geranium"}
},
{
"violet_blue",
S("Violet & Blue"),
{"flowers:viola", "flowers:geranium"}
},
{
"red_pink",
S("Red & Pink"),
{"default:rose_bush", "flowers:geranium"}
},
{
"yellow_orange",
S("Yellow & Orange"),
{"flowers:dandelion_yellow", "flowers:gerbera_daisy"}
}
}
local function add_hedge(name, desc, recipe_items)
local node_name = "blossom_hedges:" .. name.."".."hedge"
local drop_items = recipe_items
recipe_items[#recipe_items+1] = "group:leaves"
minetest.register_node(node_name, {
description = S("@1 Hedge", desc),
drawtype = "allfaces_optional",
tiles = {"flowers_" .. name .. "_hedge" .. ".png"},
wield_image = "flowers_" .. name .. "_hedge" .. ".png",
sunlight_propagates = true,
paramtype = "light",
is_ground_content = false,
groups = {snappy = 3, flammable = 2, flower = 1, flora = 1},
sounds = default.node_sound_leaves_defaults(),
drop = {
max_items = 1,
items = {
{
items = drop_items,
rarity = 1,
inherit_color = true,
}
}
}
})
minetest.register_craft({
output = node_name,
type = "shapeless",
recipe = recipe_items,
})
end
for _,item in pairs(hedges) do
add_hedge(unpack(item))
end

View File

@ -0,0 +1,7 @@
# textdomain: blossom_hedges
@1 Hedge=Seto @1
White & Blue=blanquiazul
Violet & Blue=violeta azulado
Yellow & Orange=amarillo anaranjado
Red & Pink=rojo rosáceo

View File

@ -0,0 +1,4 @@
name = blossom_hedges
description = Beautiful hedges made from flowers
depends = flowers
optional_depends =

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -141,6 +141,7 @@ minetest.register_node("baldcypress:dry_branches", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"baldcypress_dry_branches.png"},
use_texture_alpha = true,
inventory_image = "baldcypress_dry_branches.png",
wield_image = "baldcypress_dry_branches.png",
node_box = {
@ -160,6 +161,7 @@ minetest.register_node("baldcypress:liana", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"baldcypress_liana.png"},
use_texture_alpha = true,
inventory_image = "baldcypress_liana.png",
wield_image = "baldcypress_liana.png",
is_ground_content = false,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 887 B

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -147,6 +147,7 @@ minetest.register_node("ebony:creeper", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"ebony_creeper.png"},
use_texture_alpha = true,
inventory_image = "ebony_creeper.png",
wield_image = "ebony_creeper.png",
node_box = {
@ -166,6 +167,7 @@ minetest.register_node("ebony:creeper_leaves", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"ebony_creeper_leaves.png"},
use_texture_alpha = true,
inventory_image = "ebony_creeper_leaves.png",
wield_image = "ebony_creeper_leaves.png",
node_box = {
@ -185,6 +187,7 @@ minetest.register_node("ebony:liana", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"ebony_liana.png"},
use_texture_alpha = true,
inventory_image = "ebony_liana.png",
wield_image = "ebony_liana.png",
node_box = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -141,6 +141,7 @@ minetest.register_node("larch:moss", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"larch_moss.png"},
use_texture_alpha = true,
inventory_image = "larch_moss.png",
wield_image = "larch_moss.png",
node_box = {

View File

@ -147,6 +147,7 @@ minetest.register_node("mahogany:creeper", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"mahogany_creeper.png"},
use_texture_alpha = true,
inventory_image = "mahogany_creeper.png",
wield_image = "mahogany_creeper.png",
node_box = {
@ -166,6 +167,7 @@ minetest.register_node("mahogany:flower_creeper", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"mahogany_flower_creeper.png"},
use_texture_alpha = true,
inventory_image = "mahogany_flower_creeper.png",
wield_image = "mahogany_flower_creeper.png",
node_box = {
@ -185,6 +187,7 @@ minetest.register_node("mahogany:hanging_creeper", {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"mahogany_hanging_creeper.png"},
use_texture_alpha = true,
inventory_image = "mahogany_hanging_creeper.png",
wield_image = "mahogany_hanging_creeper.png",
node_box = {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,260 @@
--
-- Plumtree
--
local modname = "plumtree"
local modpath = minetest.get_modpath(modname)
local mg_name = minetest.get_mapgen_setting("mg_name")
local fruit_grow_time = 1200
-- internationalization boilerplate
local S = minetest.get_translator(minetest.get_current_modname())
-- Plum Fruit
minetest.register_node("plumtree:plum", {
description = S("Plum"),
drawtype = "plantlike",
tiles = {"plumtree_plum.png"},
inventory_image = "plumtree_plum.png",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
is_ground_content = false,
selection_box = {
type = "fixed",
fixed = {-3 / 16, -7 / 16, -3 / 16, 3 / 16, 4 / 16, 3 / 16}
},
groups = {fleshy = 3, dig_immediate = 3, flammable = 2,
leafdecay = 3, leafdecay_drop = 1},
on_use = minetest.item_eat(2),
sounds = default.node_sound_leaves_defaults(),
after_place_node = function(pos, placer, itemstack)
minetest.set_node(pos, {name = "plumtree:plum", param2 = 1})
end,
on_dig = function(pos, node, digger)
if digger:is_player() then
local inv = digger:get_inventory()
if inv:room_for_item("main", "plumtree:plum") then
inv:add_item("main", "plumtree:plum")
end
end
minetest.remove_node(pos)
pos.y = pos.y + 1
local node_above = minetest.get_node_or_nil(pos)
if node_above and node_above.param2 == 0 and node_above.name == "plumtree:blossom_leaves" then
--20% of variation on time
local twenty_percent = fruit_grow_time * 0.2
local grow_time = math.random(fruit_grow_time - twenty_percent, fruit_grow_time + twenty_percent)
minetest.get_node_timer(pos):start(grow_time)
end
end,
})
-- Plumtree
local function grow_new_plumtree_tree(pos)
if not default.can_grow(pos) then
-- try a bit later again
minetest.get_node_timer(pos):start(math.random(240, 600))
return
end
minetest.remove_node(pos)
minetest.place_schematic({x = pos.x-4, y = pos.y-1, z = pos.z-4}, modpath.."/schematics/plumtree.mts", "0", nil, true)
end
--
-- Decoration
--
if mg_name ~= "v6" and mg_name ~= "singlenode" then
local place_on
local biomes
local offset
local scale
if minetest.get_modpath("rainf") then
place_on = "rainf:meadow"
biomes = "rainf"
offset = 0.0008
scale = 0.00004
else
place_on = "default:dirt_with_grass"
biomes = "grassland"
offset = 0.00005
scale = 0.00004
end
minetest.register_decoration({
deco_type = "schematic",
place_on = {place_on},
sidelen = 16,
noise_params = {
offset = offset,
scale = scale,
spread = {x = 250, y = 250, z = 250},
seed = 23278,
octaves = 3,
persist = 0.66
},
biomes = {biomes},
y_min = 1,
y_max = 80,
schematic = modpath.."/schematics/plumtree.mts",
flags = "place_center_x, place_center_z, force_placement",
rotation = "random",
})
end
--
-- Nodes
--
minetest.register_node("plumtree:sapling", {
description = S("Plumtree Tree Sapling"),
drawtype = "plantlike",
tiles = {"plumtree_sapling.png"},
inventory_image = "plumtree_sapling.png",
wield_image = "plumtree_sapling.png",
paramtype = "light",
sunlight_propagates = true,
walkable = false,
on_timer = grow_new_plumtree_tree,
selection_box = {
type = "fixed",
fixed = {-4 / 16, -0.5, -4 / 16, 4 / 16, 7 / 16, 4 / 16}
},
groups = {snappy = 2, dig_immediate = 3, flammable = 2,
attached_node = 1, sapling = 1},
sounds = default.node_sound_leaves_defaults(),
on_construct = function(pos)
minetest.get_node_timer(pos):start(math.random(2400,4800))
end,
on_place = function(itemstack, placer, pointed_thing)
itemstack = default.sapling_on_place(itemstack, placer, pointed_thing,
"plumtree:sapling",
-- minp, maxp to be checked, relative to sapling pos
-- minp_relative.y = 1 because sapling pos has been checked
{x = -2, y = 1, z = -2},
{x = 2, y = 6, z = 2},
-- maximum interval of interior volume check
4)
return itemstack
end,
})
minetest.register_node("plumtree:trunk", {
description = S("Plumtree Trunk"),
tiles = {
"plumtree_trunk_top.png",
"plumtree_trunk_top.png",
"plumtree_trunk.png"
},
groups = {tree = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
sounds = default.node_sound_wood_defaults(),
paramtype2 = "facedir",
is_ground_content = false,
on_place = minetest.rotate_node,
})
-- plumtree wood
minetest.register_node("plumtree:wood", {
description = S("Plumtree Wood"),
tiles = {"plumtree_wood.png"},
paramtype2 = "facedir",
place_param2 = 0,
is_ground_content = false,
groups = {wood = 1, choppy = 2, oddly_breakable_by_hand = 1, flammable = 3},
sounds = default.node_sound_wood_defaults(),
})
-- plumtree tree leaves
minetest.register_node("plumtree:leaves", {
description = S("Plumtree Leaves"),
drawtype = "allfaces_optional",
tiles = {"plumtree_leaves.png"},
inventory_image = "plumtree_leaves.png",
wield_image = "plumtree_leaves.png",
paramtype = "light",
walkable = true,
waving = 1,
groups = {snappy = 3, leafdecay = 3, leaves = 1, flammable = 2},
drop = {
max_items = 1,
items = {
{items = {"plumtree:sapling"}, rarity = 20},
{items = {"plumtree:leaves"}}
}
},
sounds = default.node_sound_leaves_defaults(),
after_place_node = default.after_place_leaves,
})
--
-- Craftitems
--
--
-- Recipes
--
minetest.register_craft({
output = "plumtree:wood 4",
recipe = {{"plumtree:trunk"}}
})
minetest.register_craft({
type = "fuel",
recipe = "plumtree:trunk",
burntime = 30,
})
minetest.register_craft({
type = "fuel",
recipe = "plumtree:wood",
burntime = 7,
})
minetest.register_lbm({
name = "plumtree:convert_plumtree_saplings_to_node_timer",
nodenames = {"plumtree:sapling"},
action = function(pos)
minetest.get_node_timer(pos):start(math.random(1200, 2400))
end
})
default.register_leafdecay({
trunks = {"plumtree:trunk"},
leaves = {"plumtree:leaves"},
radius = 3,
})
--Stairs
if minetest.get_modpath("stairs") ~= nil then
stairs.register_stair_and_slab(
"plumtree_trunk",
"plumtree:trunk",
{choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
{"plumtree_wood.png"},
S("Plum Tree Stair"),
S("Plum Tree Slab"),
default.node_sound_wood_defaults()
)
end
--Support for bonemeal
if minetest.get_modpath("bonemeal") ~= nil then
bonemeal:add_sapling({
{"plumtree:sapling", grow_new_plumtree_tree, "soil"},
})
end

View File

@ -0,0 +1,11 @@
# textdomain: plumtree
Plum=Ciruela
Plumtree Trunk=Madera de ciruelo
Plumtree Wood=Tablas de ciruelo
Plumtree Leaves=Hojas de ciruelo
Plumtree Tree Sapling=Retoño de ciruelo
Plum Tree Stair=Escaleras de ciruelo
Plum Tree Slab=Losa de ciruelo
Inner Plumtree Stair=Escaleras de ciruelo interior
Outer Plumtree Stair=Escaleras de ciruelo exterior
Plumtree Slab=Losa de ciruelo

View File

@ -0,0 +1,4 @@
name = plumtree
description = Plum Tree
depends = default
optional_depends = stairs, bonemeal

View File

@ -0,0 +1,883 @@
schematic = {
size = {x=9, y=12, z=8},
yslice_prob = {
{ypos=0, prob=254},
{ypos=1, prob=254},
{ypos=2, prob=254},
{ypos=3, prob=254},
{ypos=4, prob=254},
{ypos=5, prob=254},
{ypos=6, prob=254},
{ypos=7, prob=254},
{ypos=8, prob=254},
{ypos=9, prob=254},
{ypos=10, prob=254},
{ypos=11, prob=254},
},
data = {
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:trunk", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=20},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=18},
{name="plumtree:trunk", prob=254, param2=18},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=2},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=3},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:trunk", prob=254, param2=3},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:plum", prob=254, param2=1},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="plumtree:leaves", prob=254, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
{name="air", prob=0, param2=0},
},
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -54,7 +54,7 @@ local function get_blastres(name, def)
local cracky_br = { [0] = math.huge, 200, 150, 100 }
local liquid_br = { [0] = math.huge, 200, 100, 50 }
local level_mul = { [0] = 1, 1.5, 2.5, 5 }
local res
res = math.huge
res = math.min(res, instant_br[minetest.get_item_group(name, 'dig_immediate')])
res = math.min(res, oddly_br[

View File

@ -6,8 +6,6 @@ chisel.group_style_index = {}
chisel.group_style_nodes = {}
chisel.player_copied_style = {}
chisel.register_chiselable = function(node_name, group_name, style)
chisel.chiselable[ node_name ] = {}
chisel.chiselable[ node_name ].group_name = group_name
@ -20,8 +18,6 @@ chisel.register_chiselable = function(node_name, group_name, style)
chisel.group_style_nodes[ group_name ][ style ] = node_name
end
chisel.register_chiselable_stair_and_slab = function(node_subname, group_subname, style)
chisel.register_chiselable("stairs:stair_" .. node_subname, "stairs:stair_" .. group_subname, style)
chisel.register_chiselable("stairs:stair_inner_" .. node_subname, "stairs:stair_inner_" .. group_subname, style)
@ -29,15 +25,13 @@ chisel.register_chiselable_stair_and_slab = function(node_subname, group_subname
chisel.register_chiselable("stairs:slab_" .. node_subname, "stairs:slab_" .. group_subname, style)
end
local function chisel_interact(player, pointed_thing, is_right_click)
if pointed_thing.type ~= "node" then return end
local pos = pointed_thing.under
local is_sneak = player and player:get_player_control().sneak or false
local player_name = player and player:get_player_name()
-- A true player is required
if not player_name then return end
@ -56,12 +50,11 @@ local function chisel_interact(player, pointed_thing, is_right_click)
minetest.chat_send_player(player_name, "Not chiselable")
return
end
local group_name = chisel.chiselable[ node_name ].group_name
local style = chisel.chiselable[ node_name ].style
local group = chisel.group_style_nodes[ group_name ]
local new_style , new_node_name
-- Now branch on the four user-input cases
if is_right_click then
@ -77,13 +70,14 @@ local function chisel_interact(player, pointed_thing, is_right_click)
minetest.chat_send_player(player_name, "No chisel style copied yet, use sneak + right-click to copy a style")
return
end
-- Already the correct style, exit now!
if new_style == style then return end
new_node_name = group[ new_style ]
if not new_node_name then
minetest.chat_send_player(player_name, "Chisel style " .. new_style .. " is not supported by this chisel group " .. group_name)
minetest.chat_send_player(player_name, "Chisel style " .. new_style ..
" is not supported by this chisel group " .. group_name)
return
end
end
@ -95,7 +89,7 @@ local function chisel_interact(player, pointed_thing, is_right_click)
new_style = k
new_node_name = v
end
if new_node_name == nil then
-- Not found? Go for the last element
for k,v in pairs(group) do
@ -111,16 +105,16 @@ local function chisel_interact(player, pointed_thing, is_right_click)
end
end
end
-- Check if rotation could be preserved
local nodedef = minetest.registered_nodes[node_name]
local new_nodedef = minetest.registered_nodes[new_node_name]
local rotation , new_rotation
if nodedef and new_nodedef then
if ( nodedef.paramtype2 == "facedir" or nodedef.paramtype2 == "colorfacedir" ) and ( new_nodedef.paramtype2 == "facedir" or new_nodedef.paramtype2 == "colorfacedir" ) then
rotation = node.param2 % 32 --rotation are on the last 5 digits
if ( nodedef.paramtype2 == "facedir" or nodedef.paramtype2 == "colorfacedir" )
and( new_nodedef.paramtype2 == "facedir" or new_nodedef.paramtype2 == "colorfacedir" ) then
rotation = node.param2 % 32 --rotation are on the last 5 digits
end
end
@ -131,7 +125,7 @@ local function chisel_interact(player, pointed_thing, is_right_click)
-- Copy rotation if needed!
if rotation ~= nil then
new_rotation = new_node.param2 % 32
if new_rotation ~= rotation then
new_node.param2 = new_node.param2 - new_rotation + rotation
minetest.swap_node(pos, new_node)
@ -141,8 +135,6 @@ local function chisel_interact(player, pointed_thing, is_right_click)
minetest.sound_play("jonez_carve", {pos = pos, gain = 0.7, max_hear_distance = 5})
end
--The chisel to carve the marble
minetest.register_craftitem("jonez:chisel", {
description = S("Chisel for Marble"),
@ -158,8 +150,6 @@ minetest.register_craftitem("jonez:chisel", {
end,
})
minetest.register_craft({
type = "shaped",
output = "jonez:chisel",

View File

@ -129,11 +129,12 @@ local styles = {
"medieval",
"gothic",
"pompeiian",
"corinthian"
"corinthian",
"carthaginian",
"industrial",
"romanesque"
}
-- The Crafting of the Greek Set
minetest.register_craft({
@ -176,8 +177,6 @@ minetest.register_craft({
},
})
for i = 1, #styles do
chisel.register_chiselable("jonez:"..styles[i].."_architrave", "jonez:architrave", styles[i] )
@ -232,6 +231,7 @@ for i = 1, #vines do
paramtype = "light",
paramtype2 = "facedir",
tiles = {vines[i].texture},
use_texture_alpha = true,
inventory_image = vines[i].texture,
wield_image = vines[i].texture,
node_box = {
@ -260,21 +260,27 @@ local panels = {
{"dye:green", "dye:red", "dye:orange"},
}
},
{name= "wrought_lattice_bottom", description= "Ancient Wrought Lattice (Bottom)",textures={front="jonez_wrought_lattice_bottom.png", edge="jonez_panes_edge.png"},
{name= "wrought_lattice_bottom", description= "Ancient Wrought Lattice (Bottom)",
textures={front="jonez_wrought_lattice_bottom.png", edge="jonez_panes_edge.png"},
use_texture_alpha = true,
recipe = {
{'', '', ''},
{'default:steel_ingot', 'default:tin_ingot', 'default:steel_ingot'},
{'default:steel_ingot', 'default:tin_ingot', 'default:steel_ingot'},
}
},
{name= "palace_window_top", description= "Palace Window (Top)",textures={front="jonez_palace_window_top.png", edge="default_wood.png"},
{name= "palace_window_top", description= "Palace Window (Top)",
textures={front="jonez_palace_window_top.png", edge="default_wood.png"},
use_texture_alpha = true,
recipe = {
{'', 'xpanes:pane_flat', ''},
{'', 'xpanes:pane_flat', ''},
{'', '', ''},
}
},
{name= "palace_window_bottom", description= "Palace Window (Bottom)",textures={front="jonez_palace_window_bottom.png", edge="default_wood.png"},
{name= "palace_window_bottom", description= "Palace Window (Bottom)",
textures={front="jonez_palace_window_bottom.png", edge="default_wood.png"},
use_texture_alpha = true,
recipe = {
{'', '', ''},
{'', 'xpanes:pane_flat', ''},
@ -287,6 +293,7 @@ for j=1, #panels do
xpanes.register_pane(panels[j].name, {
description = S(panels[j].description),
textures = {panels[j].textures.front, nil, panels[j].textures.edge},
use_texture_alpha = panels[j].use_texture_alpha,
inventory_image = panels[j].textures.front,
wield_image = panels[j].textures.front,
sounds = default.node_sound_glass_defaults(),
@ -375,16 +382,23 @@ local pavements= {
},
{name= "jonez:pompeiian_path", description= "Ancient Pompeiian Path", texture= "jonez_pompeiian_path.png", amount = 4,
recipe = {
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished'},
{'stairs:slab_marble_brick', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished'},
}
},
{name= "jonez:pompeiian_path", description= "Ancient Pompeiian Path", texture= "jonez_pompeiian_path.png", amount = 4,
{name= "jonez:carthaginian_pavement", description= "Carthaginian Pavement", texture= "jonez_carthaginian_pavement.png", amount = 4,
recipe = {
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'default:gravel', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick'},
}
},
{name= "jonez:carthaginian_wall", description= "Carthaginian Wall", texture= "jonez_carthaginian_wall.png", amount = 4,
recipe = {
{'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished'},
{'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick'},
{'stairs:slab_marble_brick_polished', 'stairs:slab_marble_brick', 'stairs:slab_marble_brick_polished'},
}
},
}
@ -433,6 +447,7 @@ minetest.register_node("jonez:wrought_lattice_top", {
"jonez_wrought_lattice_top.png",
"jonez_wrought_lattice_top.png"
},
use_texture_alpha = true,
})
minetest.register_craft({
@ -452,7 +467,6 @@ minetest.register_node("jonez:versailles_pavement", {
sounds = default.node_sound_stone_defaults(),
})
minetest.register_craft({
output = 'jonez:versailles_pavement',
type = "shaped",

View File

@ -20,6 +20,9 @@ Medieval=Medieval
Gothic=Gótico
Pompeiian=Pompeyano
Corinthian=Corintio
Carthaginian=Cartaginés
Industrial=Industrial
Romanesque=Romanisco
Ancient Marble Stair=Escalera de mármol antiguo
Ancient Marble Slab=Losa de mármol antiguo
Ancient Marble Brick Stair=Escalera de ladrillo de mármol antiguo
@ -54,3 +57,5 @@ Ancient Pompeiian Wall=Muro antiguo pompeyano
Ancient Pompeiian Pavement=Pavimento antiguo pompeyano
Ancient Pompeiian Path=Camino antiguo pompeyano
Ancient Pompeiian Altar=Altar antiguo pompeyano
Carthaginian Pavement=Pavimiento cartaginés
Carthaginian Wall=Pavimiento cartaginés

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -171,7 +171,8 @@ function boat.on_step(self, dtime)
end
end
local velo = self.object:get_velocity()
if self.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
if not self.driver and
self.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
self.object:set_pos(self.object:get_pos())
return
end

View File

@ -307,6 +307,7 @@ local waterlily_def = {
paramtype = "light",
paramtype2 = "facedir",
tiles = {"flowers_waterlily.png", "flowers_waterlily_bottom.png"},
use_texture_alpha = true,
inventory_image = "flowers_waterlily.png",
wield_image = "flowers_waterlily.png",
liquids_pointable = true,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

6
mods/mobkit/README.md Normal file
View File

@ -0,0 +1,6 @@
# mobkit
Entity API for Minetest
This library is meant to be shared between mods</br>
Please do not write to the mobkit namespace ('mobkit' global table),</br>
nor include own copies of mobkit in your mods and modpacks.

View File

@ -0,0 +1,830 @@
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local random = math.random
local sqrt = math.sqrt
local max = math.max
local min = math.min
local tan = math.tan
local pow = math.pow
local dbg = minetest.chat_send_all
local abr = tonumber(minetest.get_mapgen_setting('active_block_range')) or 3
local neighbors ={
{x=1,z=0},
{x=1,z=1},
{x=0,z=1},
{x=-1,z=1},
{x=-1,z=0},
{x=-1,z=-1},
{x=0,z=-1},
{x=1,z=-1}
}
function [yournamespace].dir2neighbor(dir)
dir.y=0
dir=vector.round(vector.normalize(dir))
for k,v in ipairs(neighbors) do
if v.x == dir.x and v.z == dir.z then return k end
end
return 1
end
function [yournamespace].neighbor_shift(neighbor,shift) -- int shift: minus is left, plus is right
return (8+neighbor+shift-1)%8+1
end
function [yournamespace].is_neighbor_node_reachable(self,neighbor) -- todo: take either number or pos
local offset = neighbors[neighbor]
local pos=mobkit.get_stand_pos(self)
local tpos = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
local recursteps = ceil(self.jump_height)+1
local height, liquidflag = mobkit.get_terrain_height(tpos,recursteps)
if height and abs(height-pos.y) <= self.jump_height then
tpos.y = height
height = height - pos.y
-- don't cut corners
if neighbor % 2 == 0 then -- diagonal neighbors are even
local n2 = neighbor-1 -- left neighbor never < 0
offset = neighbors[n2]
local t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
local h2 = mobkit.get_terrain_height(t2,recursteps)
if h2 and h2 - pos.y > 0.02 then return end
n2 = (neighbor+1)%8 -- right neighbor
offset = neighbors[n2]
t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
h2 = mobkit.get_terrain_height(t2,recursteps)
if h2 and h2 - pos.y > 0.02 then return end
end
-- check headroom
if tpos.y+self.height-pos.y > 1 then -- if head in next node above, else no point checking headroom
local snpos = mobkit.get_node_pos(pos)
local pos1 = {x=pos.x,y=snpos.y+1,z=pos.z} -- current pos plus node up
local pos2 = {x=tpos.x,y=tpos.y+self.height,z=tpos.z} -- target head pos
local nodes = mobkit.get_nodes_in_area(pos1,pos2,true)
for p,node in pairs(nodes) do
if snpos.x==p.x and snpos.z==p.z then
if node.name=='ignore' or node.walkable then return end
else
if node.name=='ignore' or
(node.walkable and mobkit.get_node_height(p)>tpos.y+0.001) then return end
end
end
end
return height, tpos, liquidflag
else
return
end
end
function [yournamespace].get_next_waypoint(self,tpos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = [yournamespace].dir2neighbor(dir)
local function update_pos_history(self,pos)
table.insert(self.pos_history,1,pos)
if #self.pos_history > 2 then table.remove(self.pos_history,#self.pos_history) end
end
local nogopos = self.pos_history[2]
local height, pos2, liquidflag = [yournamespace].is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
local heightl = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
local heightr = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
update_pos_history(self,pos2)
return height, pos2
else
for i=1,3 do
-- scan left
local height, pos2, liq = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,-i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
-- scan right
height, pos2, liq = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
--scan rear
height, pos2, liquidflag = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,4))
if height and not liquidflag
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
-- stuck condition here
table.remove(self.pos_history,2)
self.path_dir = self.path_dir*-1 -- subtle change in pathfinding
end
function [yournamespace].get_next_waypoint_fast(self,tpos,nogopos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = [yournamespace].dir2neighbor(dir)
local height, pos2, liquidflag = [yournamespace].is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag then
local fast = false
heightl = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
heightr = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
fast = true
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
return height, pos2, fast
else
for i=1,4 do
-- scan left
height, pos2, liq = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,-i))
if height and not liq then return height,pos2 end
-- scan right
height, pos2, liq = [yournamespace].is_neighbor_node_reachable(self,[yournamespace].neighbor_shift(neighbor,i))
if height and not liq then return height,pos2 end
end
end
end
function [yournamespace].goto_next_waypoint(self,tpos)
local height, pos2 = [yournamespace].get_next_waypoint(self,tpos)
if not height then return false end
if height <= 0.01 then
local yaw = self.object:get_yaw()
local tyaw = minetest.dir_to_yaw(vector.direction(self.object:get_pos(),pos2))
if abs(tyaw-yaw) > 1 then
[yournamespace].lq_turn2pos(self,pos2)
end
[yournamespace].lq_dumbwalk(self,pos2)
else
[yournamespace].lq_turn2pos(self,pos2)
[yournamespace].lq_dumbjump(self,height)
end
return true
end
----------------------------
-- BEHAVIORS
----------------------------
-- LOW LEVEL QUEUE FUNCTIONS
----------------------------
function [yournamespace].lq_turn2pos(self,tpos)
local func=function(self)
local pos = self.object:get_pos()
return mobkit.turn2yaw(self,
minetest.dir_to_yaw(vector.direction(pos,tpos)))
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_idle(self,duration,anim)
anim = anim or 'stand'
local init = true
local func=function(self)
if init then
mobkit.animate(self,anim)
init=false
end
duration = duration-self.dtime
if duration <= 0 then return true end
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_dumbwalk(self,dest,speed_factor)
local timer = 3 -- failsafe
speed_factor = speed_factor or 1
local func=function(self)
mobkit.animate(self,'walk')
timer = timer - self.dtime
if timer < 0 then return true end
local pos = mobkit.get_stand_pos(self)
local y = self.object:get_velocity().y
if mobkit.is_there_yet2d(pos,minetest.yaw_to_dir(self.object:get_yaw()),dest) then
-- if mobkit.isnear2d(pos,dest,0.25) then
if not self.isonground or abs(dest.y-pos.y) > 0.1 then -- prevent uncontrolled fall when velocity too high
-- if abs(dest.y-pos.y) > 0.1 then -- isonground too slow for speeds > 4
self.object:set_velocity({x=0,y=y,z=0})
end
return true
end
if self.isonground then
local dir = vector.normalize(vector.direction({x=pos.x,y=0,z=pos.z},
{x=dest.x,y=0,z=dest.z}))
dir = vector.multiply(dir,self.max_speed*speed_factor)
-- self.object:set_yaw(minetest.dir_to_yaw(dir))
mobkit.turn2yaw(self,minetest.dir_to_yaw(dir))
dir.y = y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
-- initial velocity for jump height h, v= a*sqrt(h*2/a) ,add 20%
function [yournamespace].lq_dumbjump(self,height,anim)
anim = anim or 'stand'
local jump = true
local func=function(self)
local yaw = self.object:get_yaw()
if self.isonground then
if jump then
mobkit.animate(self,anim)
local dir = minetest.yaw_to_dir(yaw)
dir.y = -mobkit.gravity*sqrt((height+0.35)*2/-mobkit.gravity)
self.object:set_velocity(dir)
jump = false
else -- the eagle has landed
return true
end
else
local dir = minetest.yaw_to_dir(yaw)
local vel = self.object:get_velocity()
if self.lastvelocity.y < 0.9 then
dir = vector.multiply(dir,3)
end
dir.y = vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_jumpout(self)
local phase = 1
local func=function(self)
local vel=self.object:get_velocity()
if phase == 1 then
vel.y=vel.y+5
self.object:set_velocity(vel)
phase = 2
else
if vel.y < 0 then return true end
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir.y=vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_freejump(self)
local phase = 1
local func=function(self)
local vel=self.object:get_velocity()
if phase == 1 then
vel.y=vel.y+6
self.object:set_velocity(vel)
phase = 2
else
if vel.y <= 0.01 then return true end
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir.y=vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_jumpattack(self,height,target)
local init=true
local timer=0.5
local tgtbox = target:get_properties().collisionbox
local func=function(self)
if not mobkit.is_alive(target) then return true end
if self.isonground then
if init then -- collision bug workaround
local vel = self.object:get_velocity()
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir=vector.multiply(dir,6)
dir.y = -mobkit.gravity*sqrt(height*2/-mobkit.gravity)
self.object:set_velocity(dir)
mobkit.make_sound(self,'charge')
init=false
else
[yournamespace].lq_idle(self,0.3)
return true
end
else
local tgtpos = target:get_pos()
local pos = self.object:get_pos()
-- calculate attack spot
local yaw = self.object:get_yaw()
local dir = minetest.yaw_to_dir(yaw)
local apos = mobkit.pos_translate2d(pos,yaw,self.attack.range)
if mobkit.is_pos_in_box(apos,tgtpos,tgtbox) then --bite
target:punch(self.object,1,self.attack)
-- bounce off
local vy = self.object:get_velocity().y
self.object:set_velocity({x=dir.x*-3,y=vy,z=dir.z*-3})
-- play attack sound if defined
mobkit.make_sound(self,'attack')
return true
end
end
end
mobkit.queue_low(self,func)
end
function [yournamespace].lq_fallover(self)
local zrot = 0
local init = true
local func=function(self)
if init then
local vel = self.object:get_velocity()
self.object:set_velocity(mobkit.pos_shift(vel,{y=1}))
mobkit.animate(self,'stand')
init = false
end
zrot=zrot+pi*0.05
local rot = self.object:get_rotation()
self.object:set_rotation({x=rot.x,y=rot.y,z=zrot})
if zrot >= pi*0.5 then return true end
end
mobkit.queue_low(self,func)
end
-----------------------------
-- HIGH LEVEL QUEUE FUNCTIONS
-----------------------------
function [yournamespace].dumbstep(self,height,tpos,speed_factor,idle_duration)
if height <= 0.001 then
[yournamespace].lq_turn2pos(self,tpos)
[yournamespace].lq_dumbwalk(self,tpos,speed_factor)
else
[yournamespace].lq_turn2pos(self,tpos)
[yournamespace].lq_dumbjump(self,height)
end
idle_duration = idle_duration or 6
[yournamespace].lq_idle(self,random(ceil(idle_duration*0.5),idle_duration))
end
function [yournamespace].hq_roam(self,prty)
local func=function(self)
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local neighbor = random(8)
local height, tpos, liquidflag = [yournamespace].is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag then [yournamespace].dumbstep(self,height,tpos,0.3) end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_follow0(self,tgtobj) -- probably delete this one
local func = function(self)
if not tgtobj then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) > 3 then
local neighbor = [yournamespace].dir2neighbor(vector.direction(pos,opos))
if not neighbor then return true end --temp debug
local height, tpos = [yournamespace].is_neighbor_node_reachable(self,neighbor)
if height then [yournamespace].dumbstep(self,height,tpos)
else
for i=1,4 do --scan left
height, tpos = [yournamespace].is_neighbor_node_reachable(self,(8+neighbor-i-1)%8+1)
if height then [yournamespace].dumbstep(self,height,tpos)
break
end --scan right
height, tpos = [yournamespace].is_neighbor_node_reachable(self,(neighbor+i-1)%8+1)
if height then [yournamespace].dumbstep(self,height,tpos)
break
end
end
end
else
[yournamespace].lq_idle(self,1)
end
end
end
mobkit.queue_high(self,func,0)
end
function [yournamespace].hq_follow(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) > 3 then
[yournamespace].goto_next_waypoint(self,opos)
else
[yournamespace].lq_idle(self,1)
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_goto(self,prty,tpos)
local func = function(self)
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
if vector.distance(pos,tpos) > 3 then
[yournamespace].goto_next_waypoint(self,tpos)
else
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_runfrom(self,prty,tgtobj)
local init=true
local timer=6
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
timer = timer-self.dtime
if timer <=0 or vector.distance(self.object:get_pos(),tgtobj:get_pos()) < 8 then
mobkit.make_sound(self,'scared')
init=false
end
return
end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) < self.view_range*1.1 then
local tpos = {x=2*pos.x - opos.x,
y=opos.y,
z=2*pos.z - opos.z}
[yournamespace].goto_next_waypoint(self,tpos)
else
self.object:set_velocity({x=0,y=0,z=0})
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_hunt(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
local dist = vector.distance(pos,opos)
if dist > self.view_range then
return true
elseif dist > 3 then
[yournamespace].goto_next_waypoint(self,opos)
else
[yournamespace].hq_attack(self,prty+1,tgtobj)
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_warn(self,prty,tgtobj)
local timer=0
local tgttime = 0
local init = true
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
mobkit.animate(self,'stand')
init = false
end
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
local dist = vector.distance(pos,opos)
if dist > 11 then
return true
elseif dist < 4 or timer > 12 then -- too close man
-- mobkit.clear_queue_high(self)
mobkit.remember(self,'hate',tgtobj:get_player_name())
[yournamespace].hq_hunt(self,prty+1,tgtobj) -- priority
else
timer = timer+self.dtime
if mobkit.is_queue_empty_low(self) then
[yournamespace].lq_turn2pos(self,opos)
end
-- make noise in random intervals
if timer > tgttime then
mobkit.make_sound(self,'warn')
-- if self.sounds and self.sounds.warn then
-- minetest.sound_play(self.sounds.warn, {object=self.object})
-- end
tgttime = timer + 1.1 + random()*1.5
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_die(self)
local timer = 5
local start = true
local func = function(self)
if start then
[yournamespace].lq_fallover(self)
self.logic = function(self) end -- brain dead as well
start=false
end
timer = timer-self.dtime
if timer < 0 then self.object:remove() end
end
mobkit.queue_high(self,func,100)
end
function [yournamespace].hq_attack(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
-- local tpos = tgtobj:get_pos()
local tpos = mobkit.get_stand_pos(tgtobj)
local dist = vector.distance(pos,tpos)
if dist > 3 then
return true
else
[yournamespace].lq_turn2pos(self,tpos)
local height = tgtobj:is_player() and 0.35 or tgtobj:get_luaentity().height*0.6
if tpos.y+height>pos.y then
[yournamespace].lq_jumpattack(self,tpos.y+height-pos.y,tgtobj)
else
[yournamespace].lq_dumbwalk(self,mobkit.pos_shift(tpos,{x=random()-0.5,z=random()-0.5}))
end
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_liquid_recovery(self,prty) -- scan for nearest land
local radius = 1
local yaw = 0
local func = function(self)
if not self.isinliquid then return true end
local pos=self.object:get_pos()
local vec = minetest.yaw_to_dir(yaw)
local pos2 = mobkit.pos_shift(pos,vector.multiply(vec,radius))
local height, liquidflag = mobkit.get_terrain_height(pos2)
if height and not liquidflag then
[yournamespace].hq_swimto(self,prty,pos2)
return true
end
yaw=yaw+pi*0.25
if yaw>2*pi then
yaw = 0
radius=radius+1
if radius > self.view_range then
self.hp = 0
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_swimto(self,prty,tpos)
local box = self.object:get_properties().collisionbox
local cols = {}
local func = function(self)
if not self.isinliquid then
if self.isonground then return true end
return false
end
local pos = mobkit.get_stand_pos(self)
local y=self.object:get_velocity().y
local pos2d = {x=pos.x,y=tpos.y,z=pos.z}
local dir=vector.normalize(vector.direction(pos2d,tpos))
local yaw = minetest.dir_to_yaw(dir)
if mobkit.timer(self,1) then
cols = mobkit.get_box_displace_cols(pos,box,dir,1)
for _,p in ipairs(cols) do
p.y=pos.y
local h,l = mobkit.get_terrain_height(p)
if h and h>pos.y and self.isinliquid then
[yournamespace].lq_freejump(self)
break
end
end
elseif mobkit.turn2yaw(self,yaw) then
dir.y = y
self.object:set_velocity(dir)
end
end
mobkit.queue_high(self,func,prty)
end
---------------------
-- AQUATIC
---------------------
-- MACROS
local function aqua_radar_dumb(pos,yaw,range,reverse)
range = range or 4
local function okpos(p)
local node = mobkit.nodeatpos(p)
if node then
if node.drawtype == 'liquid' then
local nodeu = mobkit.nodeatpos(mobkit.pos_shift(p,{y=1}))
local noded = mobkit.nodeatpos(mobkit.pos_shift(p,{y=-1}))
if (nodeu and nodeu.drawtype == 'liquid') or (noded and noded.drawtype == 'liquid') then
return true
else
return false
end
else
local h,l = mobkit.get_terrain_height(p)
if h then
local node2 = mobkit.nodeatpos({x=p.x,y=h+1.99,z=p.z})
if node2 and node2.drawtype == 'liquid' then return true, h end
else
return false
end
end
else
return false
end
end
local fpos = mobkit.pos_translate2d(pos,yaw,range)
local ok,h = okpos(fpos)
if not ok then
local ffrom, fto, fstep
if reverse then
ffrom, fto, fstep = 3,1,-1
else
ffrom, fto, fstep = 1,3,1
end
for i=ffrom, fto, fstep do
local ok,h = okpos(mobkit.pos_translate2d(pos,yaw+i,range))
if ok then return yaw+i,h end
ok,h = okpos(mobkit.pos_translate2d(pos,yaw-i,range))
if ok then return yaw-i,h end
end
return yaw+pi,h
else
return yaw, h
end
end
function [yournamespace].is_in_deep(target)
if not target then return false end
local nodepos = mobkit.get_stand_pos(target)
local node1 = mobkit.nodeatpos(nodepos)
nodepos.y=nodepos.y+1
local node2 = mobkit.nodeatpos(nodepos)
nodepos.y=nodepos.y-2
local node3 = mobkit.nodeatpos(nodepos)
if node1 and node2 and node3 and node1.drawtype=='liquid' and (node2.drawtype=='liquid' or node3.drawtype=='liquid') then
return true
end
end
-- HQ behaviors
function [yournamespace].hq_aqua_roam(self,prty,speed)
local tyaw = 0
local init = true
local prvscanpos = {x=0,y=0,z=0}
local center = self.object:get_pos()
local func = function(self)
if init then
mobkit.animate(self,'def')
init = false
end
local pos = mobkit.get_stand_pos(self)
local yaw = self.object:get_yaw()
local scanpos = mobkit.get_node_pos(mobkit.pos_translate2d(pos,yaw,speed))
if not vector.equals(prvscanpos,scanpos) then
prvscanpos=scanpos
local nyaw,height = aqua_radar_dumb(pos,yaw,speed,true)
if height and height > pos.y then
local vel = self.object:get_velocity()
vel.y = vel.y+1
self.object:set_velocity(vel)
end
if yaw ~= nyaw then
tyaw=nyaw
[yournamespace].hq_aqua_turn(self,prty+1,tyaw,speed)
return
end
end
if mobkit.timer(self,1) then
if vector.distance(pos,center) > abr*16*0.5 then
tyaw = minetest.dir_to_yaw(vector.direction(pos,{x=center.x+random()*10-5,y=center.y,z=center.z+random()*10-5}))
else
if random(10)>=9 then tyaw=tyaw+random()*pi - pi*0.5 end
end
end
mobkit.turn2yaw(self,tyaw,3)
-- local yaw = self.object:get_yaw()
mobkit.go_forward_horizontal(self,speed)
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_aqua_turn(self,prty,tyaw,speed)
local func = function(self)
local finished=mobkit.turn2yaw(self,tyaw)
-- local yaw = self.object:get_yaw()
mobkit.go_forward_horizontal(self,speed)
if finished then return true end
end
mobkit.queue_high(self,func,prty)
end
function [yournamespace].hq_aqua_attack(self,prty,tgtobj,speed)
local tyaw = 0
local prvscanpos = {x=0,y=0,z=0}
local init = true
local tgtbox = tgtobj:get_properties().collisionbox
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
mobkit.animate(self,'fast')
mobkit.make_sound(self,'attack')
init = false
end
local pos = mobkit.get_stand_pos(self)
local yaw = self.object:get_yaw()
local scanpos = mobkit.get_node_pos(mobkit.pos_translate2d(pos,yaw,speed))
if not vector.equals(prvscanpos,scanpos) then
prvscanpos=scanpos
local nyaw,height = aqua_radar_dumb(pos,yaw,speed*0.5)
if height and height > pos.y then
local vel = self.object:get_velocity()
vel.y = vel.y+1
self.object:set_velocity(vel)
end
if yaw ~= nyaw then
tyaw=nyaw
[yournamespace].hq_aqua_turn(self,prty+1,tyaw,speed)
return
end
end
local tpos = tgtobj:get_pos()
local tyaw=minetest.dir_to_yaw(vector.direction(pos,tpos))
mobkit.turn2yaw(self,tyaw,3)
local yaw = self.object:get_yaw()
if mobkit.timer(self,1) then
if not [yournamespace].is_in_deep(tgtobj) then return true end
local vel = self.object:get_velocity()
if tpos.y>pos.y+0.5 then self.object:set_velocity({x=vel.x,y=vel.y+0.5,z=vel.z})
elseif tpos.y<pos.y-0.5 then self.object:set_velocity({x=vel.x,y=vel.y-0.5,z=vel.z}) end
end
if mobkit.is_pos_in_box(mobkit.pos_translate2d(pos,yaw,self.attack.range),tpos,tgtbox) then --bite
tgtobj:punch(self.object,1,self.attack)
[yournamespace].hq_aqua_turn(self,prty,yaw-pi,speed)
return true
end
mobkit.go_forward_horizontal(self,speed)
end
mobkit.queue_high(self,func,prty)
end

View File

@ -0,0 +1,830 @@
local abs = math.abs
local pi = math.pi
local floor = math.floor
local ceil = math.ceil
local random = math.random
local sqrt = math.sqrt
local max = math.max
local min = math.min
local tan = math.tan
local pow = math.pow
local dbg = minetest.chat_send_all
local abr = tonumber(minetest.get_mapgen_setting('active_block_range')) or 3
local neighbors ={
{x=1,z=0},
{x=1,z=1},
{x=0,z=1},
{x=-1,z=1},
{x=-1,z=0},
{x=-1,z=-1},
{x=0,z=-1},
{x=1,z=-1}
}
function mobkit.dir2neighbor(dir)
dir.y=0
dir=vector.round(vector.normalize(dir))
for k,v in ipairs(neighbors) do
if v.x == dir.x and v.z == dir.z then return k end
end
return 1
end
function mobkit.neighbor_shift(neighbor,shift) -- int shift: minus is left, plus is right
return (8+neighbor+shift-1)%8+1
end
function mobkit.is_neighbor_node_reachable(self,neighbor) -- todo: take either number or pos
local offset = neighbors[neighbor]
local pos=mobkit.get_stand_pos(self)
local tpos = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
local recursteps = ceil(self.jump_height)+1
local height, liquidflag = mobkit.get_terrain_height(tpos,recursteps)
if height and abs(height-pos.y) <= self.jump_height then
tpos.y = height
height = height - pos.y
-- don't cut corners
if neighbor % 2 == 0 then -- diagonal neighbors are even
local n2 = neighbor-1 -- left neighbor never < 0
offset = neighbors[n2]
local t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
local h2 = mobkit.get_terrain_height(t2,recursteps)
if h2 and h2 - pos.y > 0.02 then return end
n2 = (neighbor+1)%8 -- right neighbor
offset = neighbors[n2]
t2 = mobkit.get_node_pos(mobkit.pos_shift(pos,offset))
h2 = mobkit.get_terrain_height(t2,recursteps)
if h2 and h2 - pos.y > 0.02 then return end
end
-- check headroom
if tpos.y+self.height-pos.y > 1 then -- if head in next node above, else no point checking headroom
local snpos = mobkit.get_node_pos(pos)
local pos1 = {x=pos.x,y=snpos.y+1,z=pos.z} -- current pos plus node up
local pos2 = {x=tpos.x,y=tpos.y+self.height,z=tpos.z} -- target head pos
local nodes = mobkit.get_nodes_in_area(pos1,pos2,true)
for p,node in pairs(nodes) do
if snpos.x==p.x and snpos.z==p.z then
if node.name=='ignore' or node.walkable then return end
else
if node.name=='ignore' or
(node.walkable and mobkit.get_node_height(p)>tpos.y+0.001) then return end
end
end
end
return height, tpos, liquidflag
else
return
end
end
function mobkit.get_next_waypoint(self,tpos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = mobkit.dir2neighbor(dir)
local function update_pos_history(self,pos)
table.insert(self.pos_history,1,pos)
if #self.pos_history > 2 then table.remove(self.pos_history,#self.pos_history) end
end
local nogopos = self.pos_history[2]
local height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
local heightl = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
local heightr = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
update_pos_history(self,pos2)
return height, pos2
else
for i=1,3 do
-- scan left
local height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
-- scan right
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,i*self.path_dir))
if height and not liq
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
--scan rear
height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,4))
if height and not liquidflag
and not (nogopos and mobkit.isnear2d(pos2,nogopos,0.1)) then
update_pos_history(self,pos2)
return height,pos2
end
end
-- stuck condition here
table.remove(self.pos_history,2)
self.path_dir = self.path_dir*-1 -- subtle change in pathfinding
end
function mobkit.get_next_waypoint_fast(self,tpos,nogopos)
local pos = mobkit.get_stand_pos(self)
local dir=vector.direction(pos,tpos)
local neighbor = mobkit.dir2neighbor(dir)
local height, pos2, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag then
local fast = false
heightl = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-1))
if heightl and abs(heightl-height)<0.001 then
heightr = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,1))
if heightr and abs(heightr-height)<0.001 then
fast = true
dir.y = 0
local dirn = vector.normalize(dir)
local npos = mobkit.get_node_pos(mobkit.pos_shift(pos,neighbors[neighbor]))
local factor = abs(dirn.x) > abs(dirn.z) and abs(npos.x-pos.x) or abs(npos.z-pos.z)
pos2=mobkit.pos_shift(pos,{x=dirn.x*factor,z=dirn.z*factor})
end
end
return height, pos2, fast
else
for i=1,4 do
-- scan left
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,-i))
if height and not liq then return height,pos2 end
-- scan right
height, pos2, liq = mobkit.is_neighbor_node_reachable(self,mobkit.neighbor_shift(neighbor,i))
if height and not liq then return height,pos2 end
end
end
end
function mobkit.goto_next_waypoint(self,tpos)
local height, pos2 = mobkit.get_next_waypoint(self,tpos)
if not height then return false end
if height <= 0.01 then
local yaw = self.object:get_yaw()
local tyaw = minetest.dir_to_yaw(vector.direction(self.object:get_pos(),pos2))
if abs(tyaw-yaw) > 1 then
mobkit.lq_turn2pos(self,pos2)
end
mobkit.lq_dumbwalk(self,pos2)
else
mobkit.lq_turn2pos(self,pos2)
mobkit.lq_dumbjump(self,height)
end
return true
end
----------------------------
-- BEHAVIORS
----------------------------
-- LOW LEVEL QUEUE FUNCTIONS
----------------------------
function mobkit.lq_turn2pos(self,tpos)
local func=function(self)
local pos = self.object:get_pos()
return mobkit.turn2yaw(self,
minetest.dir_to_yaw(vector.direction(pos,tpos)))
end
mobkit.queue_low(self,func)
end
function mobkit.lq_idle(self,duration,anim)
anim = anim or 'stand'
local init = true
local func=function(self)
if init then
mobkit.animate(self,anim)
init=false
end
duration = duration-self.dtime
if duration <= 0 then return true end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_dumbwalk(self,dest,speed_factor)
local timer = 3 -- failsafe
speed_factor = speed_factor or 1
local func=function(self)
mobkit.animate(self,'walk')
timer = timer - self.dtime
if timer < 0 then return true end
local pos = mobkit.get_stand_pos(self)
local y = self.object:get_velocity().y
if mobkit.is_there_yet2d(pos,minetest.yaw_to_dir(self.object:get_yaw()),dest) then
-- if mobkit.isnear2d(pos,dest,0.25) then
if not self.isonground or abs(dest.y-pos.y) > 0.1 then -- prevent uncontrolled fall when velocity too high
-- if abs(dest.y-pos.y) > 0.1 then -- isonground too slow for speeds > 4
self.object:set_velocity({x=0,y=y,z=0})
end
return true
end
if self.isonground then
local dir = vector.normalize(vector.direction({x=pos.x,y=0,z=pos.z},
{x=dest.x,y=0,z=dest.z}))
dir = vector.multiply(dir,self.max_speed*speed_factor)
-- self.object:set_yaw(minetest.dir_to_yaw(dir))
mobkit.turn2yaw(self,minetest.dir_to_yaw(dir))
dir.y = y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
-- initial velocity for jump height h, v= a*sqrt(h*2/a) ,add 20%
function mobkit.lq_dumbjump(self,height,anim)
anim = anim or 'stand'
local jump = true
local func=function(self)
local yaw = self.object:get_yaw()
if self.isonground then
if jump then
mobkit.animate(self,anim)
local dir = minetest.yaw_to_dir(yaw)
dir.y = -mobkit.gravity*sqrt((height+0.35)*2/-mobkit.gravity)
self.object:set_velocity(dir)
jump = false
else -- the eagle has landed
return true
end
else
local dir = minetest.yaw_to_dir(yaw)
local vel = self.object:get_velocity()
if self.lastvelocity.y < 0.9 then
dir = vector.multiply(dir,3)
end
dir.y = vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_jumpout(self)
local phase = 1
local func=function(self)
local vel=self.object:get_velocity()
if phase == 1 then
vel.y=vel.y+5
self.object:set_velocity(vel)
phase = 2
else
if vel.y < 0 then return true end
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir.y=vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_freejump(self)
local phase = 1
local func=function(self)
local vel=self.object:get_velocity()
if phase == 1 then
vel.y=vel.y+6
self.object:set_velocity(vel)
phase = 2
else
if vel.y <= 0.01 then return true end
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir.y=vel.y
self.object:set_velocity(dir)
end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_jumpattack(self,height,target)
local init=true
local timer=0.5
local tgtbox = target:get_properties().collisionbox
local func=function(self)
if not mobkit.is_alive(target) then return true end
if self.isonground then
if init then -- collision bug workaround
local vel = self.object:get_velocity()
local dir = minetest.yaw_to_dir(self.object:get_yaw())
dir=vector.multiply(dir,6)
dir.y = -mobkit.gravity*sqrt(height*2/-mobkit.gravity)
self.object:set_velocity(dir)
mobkit.make_sound(self,'charge')
init=false
else
mobkit.lq_idle(self,0.3)
return true
end
else
local tgtpos = target:get_pos()
local pos = self.object:get_pos()
-- calculate attack spot
local yaw = self.object:get_yaw()
local dir = minetest.yaw_to_dir(yaw)
local apos = mobkit.pos_translate2d(pos,yaw,self.attack.range)
if mobkit.is_pos_in_box(apos,tgtpos,tgtbox) then --bite
target:punch(self.object,1,self.attack)
-- bounce off
local vy = self.object:get_velocity().y
self.object:set_velocity({x=dir.x*-3,y=vy,z=dir.z*-3})
-- play attack sound if defined
mobkit.make_sound(self,'attack')
return true
end
end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_fallover(self)
local zrot = 0
local init = true
local func=function(self)
if init then
local vel = self.object:get_velocity()
self.object:set_velocity(mobkit.pos_shift(vel,{y=1}))
mobkit.animate(self,'stand')
init = false
end
zrot=zrot+pi*0.05
local rot = self.object:get_rotation()
self.object:set_rotation({x=rot.x,y=rot.y,z=zrot})
if zrot >= pi*0.5 then return true end
end
mobkit.queue_low(self,func)
end
-----------------------------
-- HIGH LEVEL QUEUE FUNCTIONS
-----------------------------
function mobkit.dumbstep(self,height,tpos,speed_factor,idle_duration)
if height <= 0.001 then
mobkit.lq_turn2pos(self,tpos)
mobkit.lq_dumbwalk(self,tpos,speed_factor)
else
mobkit.lq_turn2pos(self,tpos)
mobkit.lq_dumbjump(self,height)
end
idle_duration = idle_duration or 6
mobkit.lq_idle(self,random(ceil(idle_duration*0.5),idle_duration))
end
function mobkit.hq_roam(self,prty)
local func=function(self)
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local neighbor = random(8)
local height, tpos, liquidflag = mobkit.is_neighbor_node_reachable(self,neighbor)
if height and not liquidflag then mobkit.dumbstep(self,height,tpos,0.3) end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_follow0(self,tgtobj) -- probably delete this one
local func = function(self)
if not tgtobj then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) > 3 then
local neighbor = mobkit.dir2neighbor(vector.direction(pos,opos))
if not neighbor then return true end --temp debug
local height, tpos = mobkit.is_neighbor_node_reachable(self,neighbor)
if height then mobkit.dumbstep(self,height,tpos)
else
for i=1,4 do --scan left
height, tpos = mobkit.is_neighbor_node_reachable(self,(8+neighbor-i-1)%8+1)
if height then mobkit.dumbstep(self,height,tpos)
break
end --scan right
height, tpos = mobkit.is_neighbor_node_reachable(self,(neighbor+i-1)%8+1)
if height then mobkit.dumbstep(self,height,tpos)
break
end
end
end
else
mobkit.lq_idle(self,1)
end
end
end
mobkit.queue_high(self,func,0)
end
function mobkit.hq_follow(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) > 3 then
mobkit.goto_next_waypoint(self,opos)
else
mobkit.lq_idle(self,1)
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_goto(self,prty,tpos)
local func = function(self)
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
if vector.distance(pos,tpos) > 3 then
mobkit.goto_next_waypoint(self,tpos)
else
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_runfrom(self,prty,tgtobj)
local init=true
local timer=6
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
timer = timer-self.dtime
if timer <=0 or vector.distance(self.object:get_pos(),tgtobj:get_pos()) < 8 then
mobkit.make_sound(self,'scared')
init=false
end
return
end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
if vector.distance(pos,opos) < self.view_range*1.1 then
local tpos = {x=2*pos.x - opos.x,
y=opos.y,
z=2*pos.z - opos.z}
mobkit.goto_next_waypoint(self,tpos)
else
self.object:set_velocity({x=0,y=0,z=0})
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_hunt(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) and self.isonground then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
local dist = vector.distance(pos,opos)
if dist > self.view_range then
return true
elseif dist > 3 then
mobkit.goto_next_waypoint(self,opos)
else
mobkit.hq_attack(self,prty+1,tgtobj)
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_warn(self,prty,tgtobj)
local timer=0
local tgttime = 0
local init = true
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
mobkit.animate(self,'stand')
init = false
end
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
local dist = vector.distance(pos,opos)
if dist > 11 then
return true
elseif dist < 4 or timer > 12 then -- too close man
-- mobkit.clear_queue_high(self)
mobkit.remember(self,'hate',tgtobj:get_player_name())
mobkit.hq_hunt(self,prty+1,tgtobj) -- priority
else
timer = timer+self.dtime
if mobkit.is_queue_empty_low(self) then
mobkit.lq_turn2pos(self,opos)
end
-- make noise in random intervals
if timer > tgttime then
mobkit.make_sound(self,'warn')
-- if self.sounds and self.sounds.warn then
-- minetest.sound_play(self.sounds.warn, {object=self.object})
-- end
tgttime = timer + 1.1 + random()*1.5
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_die(self)
local timer = 5
local start = true
local func = function(self)
if start then
mobkit.lq_fallover(self)
self.logic = function(self) end -- brain dead as well
start=false
end
timer = timer-self.dtime
if timer < 0 then self.object:remove() end
end
mobkit.queue_high(self,func,100)
end
function mobkit.hq_attack(self,prty,tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
-- local tpos = tgtobj:get_pos()
local tpos = mobkit.get_stand_pos(tgtobj)
local dist = vector.distance(pos,tpos)
if dist > 3 then
return true
else
mobkit.lq_turn2pos(self,tpos)
local height = tgtobj:is_player() and 0.35 or tgtobj:get_luaentity().height*0.6
if tpos.y+height>pos.y then
mobkit.lq_jumpattack(self,tpos.y+height-pos.y,tgtobj)
else
mobkit.lq_dumbwalk(self,mobkit.pos_shift(tpos,{x=random()-0.5,z=random()-0.5}))
end
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_liquid_recovery(self,prty) -- scan for nearest land
local radius = 1
local yaw = 0
local func = function(self)
if not self.isinliquid then return true end
local pos=self.object:get_pos()
local vec = minetest.yaw_to_dir(yaw)
local pos2 = mobkit.pos_shift(pos,vector.multiply(vec,radius))
local height, liquidflag = mobkit.get_terrain_height(pos2)
if height and not liquidflag then
mobkit.hq_swimto(self,prty,pos2)
return true
end
yaw=yaw+pi*0.25
if yaw>2*pi then
yaw = 0
radius=radius+1
if radius > self.view_range then
self.hp = 0
return true
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_swimto(self,prty,tpos)
local box = self.object:get_properties().collisionbox
local cols = {}
local func = function(self)
if not self.isinliquid then
if self.isonground then return true end
return false
end
local pos = mobkit.get_stand_pos(self)
local y=self.object:get_velocity().y
local pos2d = {x=pos.x,y=tpos.y,z=pos.z}
local dir=vector.normalize(vector.direction(pos2d,tpos))
local yaw = minetest.dir_to_yaw(dir)
if mobkit.timer(self,1) then
cols = mobkit.get_box_displace_cols(pos,box,dir,1)
for _,p in ipairs(cols) do
p.y=pos.y
local h,l = mobkit.get_terrain_height(p)
if h and h>pos.y and self.isinliquid then
mobkit.lq_freejump(self)
break
end
end
elseif mobkit.turn2yaw(self,yaw) then
dir.y = y
self.object:set_velocity(dir)
end
end
mobkit.queue_high(self,func,prty)
end
---------------------
-- AQUATIC
---------------------
-- MACROS
local function aqua_radar_dumb(pos,yaw,range,reverse)
range = range or 4
local function okpos(p)
local node = mobkit.nodeatpos(p)
if node then
if node.drawtype == 'liquid' then
local nodeu = mobkit.nodeatpos(mobkit.pos_shift(p,{y=1}))
local noded = mobkit.nodeatpos(mobkit.pos_shift(p,{y=-1}))
if (nodeu and nodeu.drawtype == 'liquid') or (noded and noded.drawtype == 'liquid') then
return true
else
return false
end
else
local h,l = mobkit.get_terrain_height(p)
if h then
local node2 = mobkit.nodeatpos({x=p.x,y=h+1.99,z=p.z})
if node2 and node2.drawtype == 'liquid' then return true, h end
else
return false
end
end
else
return false
end
end
local fpos = mobkit.pos_translate2d(pos,yaw,range)
local ok,h = okpos(fpos)
if not ok then
local ffrom, fto, fstep
if reverse then
ffrom, fto, fstep = 3,1,-1
else
ffrom, fto, fstep = 1,3,1
end
for i=ffrom, fto, fstep do
local ok,h = okpos(mobkit.pos_translate2d(pos,yaw+i,range))
if ok then return yaw+i,h end
ok,h = okpos(mobkit.pos_translate2d(pos,yaw-i,range))
if ok then return yaw-i,h end
end
return yaw+pi,h
else
return yaw, h
end
end
function mobkit.is_in_deep(target)
if not target then return false end
local nodepos = mobkit.get_stand_pos(target)
local node1 = mobkit.nodeatpos(nodepos)
nodepos.y=nodepos.y+1
local node2 = mobkit.nodeatpos(nodepos)
nodepos.y=nodepos.y-2
local node3 = mobkit.nodeatpos(nodepos)
if node1 and node2 and node3 and node1.drawtype=='liquid' and (node2.drawtype=='liquid' or node3.drawtype=='liquid') then
return true
end
end
-- HQ behaviors
function mobkit.hq_aqua_roam(self,prty,speed)
local tyaw = 0
local init = true
local prvscanpos = {x=0,y=0,z=0}
local center = self.object:get_pos()
local func = function(self)
if init then
mobkit.animate(self,'def')
init = false
end
local pos = mobkit.get_stand_pos(self)
local yaw = self.object:get_yaw()
local scanpos = mobkit.get_node_pos(mobkit.pos_translate2d(pos,yaw,speed))
if not vector.equals(prvscanpos,scanpos) then
prvscanpos=scanpos
local nyaw,height = aqua_radar_dumb(pos,yaw,speed,true)
if height and height > pos.y then
local vel = self.object:get_velocity()
vel.y = vel.y+1
self.object:set_velocity(vel)
end
if yaw ~= nyaw then
tyaw=nyaw
mobkit.hq_aqua_turn(self,prty+1,tyaw,speed)
return
end
end
if mobkit.timer(self,1) then
if vector.distance(pos,center) > abr*16*0.5 then
tyaw = minetest.dir_to_yaw(vector.direction(pos,{x=center.x+random()*10-5,y=center.y,z=center.z+random()*10-5}))
else
if random(10)>=9 then tyaw=tyaw+random()*pi - pi*0.5 end
end
end
mobkit.turn2yaw(self,tyaw,3)
-- local yaw = self.object:get_yaw()
mobkit.go_forward_horizontal(self,speed)
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_aqua_turn(self,prty,tyaw,speed)
local func = function(self)
local finished=mobkit.turn2yaw(self,tyaw)
-- local yaw = self.object:get_yaw()
mobkit.go_forward_horizontal(self,speed)
if finished then return true end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_aqua_attack(self,prty,tgtobj,speed)
local tyaw = 0
local prvscanpos = {x=0,y=0,z=0}
local init = true
local tgtbox = tgtobj:get_properties().collisionbox
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if init then
mobkit.animate(self,'fast')
mobkit.make_sound(self,'attack')
init = false
end
local pos = mobkit.get_stand_pos(self)
local yaw = self.object:get_yaw()
local scanpos = mobkit.get_node_pos(mobkit.pos_translate2d(pos,yaw,speed))
if not vector.equals(prvscanpos,scanpos) then
prvscanpos=scanpos
local nyaw,height = aqua_radar_dumb(pos,yaw,speed*0.5)
if height and height > pos.y then
local vel = self.object:get_velocity()
vel.y = vel.y+1
self.object:set_velocity(vel)
end
if yaw ~= nyaw then
tyaw=nyaw
mobkit.hq_aqua_turn(self,prty+1,tyaw,speed)
return
end
end
local tpos = tgtobj:get_pos()
local tyaw=minetest.dir_to_yaw(vector.direction(pos,tpos))
mobkit.turn2yaw(self,tyaw,3)
local yaw = self.object:get_yaw()
if mobkit.timer(self,1) then
if not mobkit.is_in_deep(tgtobj) then return true end
local vel = self.object:get_velocity()
if tpos.y>pos.y+0.5 then self.object:set_velocity({x=vel.x,y=vel.y+0.5,z=vel.z})
elseif tpos.y<pos.y-0.5 then self.object:set_velocity({x=vel.x,y=vel.y-0.5,z=vel.z}) end
end
if mobkit.is_pos_in_box(mobkit.pos_translate2d(pos,yaw,self.attack.range),tpos,tgtbox) then --bite
tgtobj:punch(self.object,1,self.attack)
mobkit.hq_aqua_turn(self,prty,yaw-pi,speed)
return true
end
mobkit.go_forward_horizontal(self,speed)
end
mobkit.queue_high(self,func,prty)
end

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@ Contents
1.1.1 Low level functions
1.1.2 High level functions
1.1.2.1 Priority
1.1.3 Modifying built in behaviors
1.2 Logic function
1.3 Processing diagram
1.4 Entity definition
@ -37,8 +38,9 @@ They signal finished state by returning true, therefore it's very important to c
For a behavior to begin executing it has to be put on a queue. There are two separate queues, one for low and one for high level behaviors.
Queuing is covered by behavour defining conventions
!!! In simplest scenarios there's no need to code behaviors, much can be achieved using only built-in stuff !!!
!!! To start using the api it's enough to learn defining mobs and writing brain functions !!!
Mobkit comes with some example behavior functions, which are located in /example_behaviors.lua
!!! In simplest scenarios there's no need to code behaviors, much can be achieved using only built-in stuff !!!
!!! To start using the api it's enough to learn defining mobs and writing brain functions !!!
1.1.1 Low level behavior functions
@ -99,6 +101,10 @@ hq_bhv1(self,prty):
Particular prioritization scheme is to be designed by the user according to specific mod requirements.
1.1.3 Modifying built in behaviors
Do not modify example_behaviors.lua directly, because functions defined there are meant to be shared between mods.
Instead, copy the contents of /behaviors2override.lua into your mod/game, changing every occurence of the string '[yournamespace]' to the name of a lua table representing your namespace of choice.
1.2 Logic function
------------------
@ -138,22 +144,22 @@ end
----------------------
---------------------------------------
| PHYSICS |
| |
| ----------------------- |
| | Logic Function | |
| ----------------------- |
| | |
| -----|----------------- |
| | V HL Queue | |
| | | 1 | 2 | 3 |... | |
| ----------------------- |
| | |
| -----|----------------- |
| | V LL Queue | |
| | | 1 | 2 | 3 |... | |
| ----------------------- |
| |
| PHYSICS |
| |
| ----------------------- |
| | Logic Function | |
| ----------------------- |
| | |
| -----|----------------- |
| | V HL Queue| |
| | 1| 2| 3|... | |
| ----------------------- |
| | |
| -----|----------------- |
| | V LL Queue| |
| | 1| 2| 3|... | |
| ----------------------- |
| |
---------------------------------------
Order of execution during an engine step:
@ -250,7 +256,7 @@ Some frequently used entity fields to be accessed directly for convenience
self.dtime -- max(dtime as passed to on_step,0.5) - limit of 0.05 to prevent jerkines on long steps.
self.hp -- hitpoints
self.isonground -- true if pos.y remains unchanged for 2 consecutive steps
self.isonground -- true if in collision with negative Y
self.isinliquid -- true if the node at foot level is drawtype=='liquid'
------------
@ -318,6 +324,13 @@ function mobkit.is_there_yet2d(pos,dir,dest) -- obj positon; facing vector; dest
function mobkit.isnear3d(p1,p2,thresh)
-- returns true if pos p2 is within a cube with center at pos p1 and radius thresh
function mobkit.get_box_intersect_cols(pos,box)
-- returns an array of {x=,z=} columns that the box intersects with.
function mobkit.get_box_displace_cols(pos,box,vec,dist)
-- returns an array of {x=,z=} columns that the box would pass by if moved by horizontal vector vec
-- if dist provided, vec gets normalized.
function mobkit.dir_to_rot(v,rot)
-- converts a 3d vector v to rotation like in set_rotation() object method
-- rot (optional) is current object rotation

23
mods/petz/.gitignore vendored
View File

@ -1,25 +1,4 @@
## Generic ignorable patterns and files
*.obj
*.blend1
user.conf
globals = {
"minetest",
"mobkit",
"stairs",
"bucket",
"armors",
"bonemeal"
}
read_globals = {
string = {fields = {"split"}},
table = {fields = {"copy", "getn"}},
-- Builtin
"vector", "ItemStack",
"dump", "DIR_DELIM", "VoxelArea", "Settings",
-- MTG
"default", "sfinv", "creative",
}
user.conf

View File

@ -13,8 +13,9 @@ globals = {
"hunger_ng",
"dye",
"armor",
"player_physics",
"player_monoids"
"playerphysics",
"player_monoids",
"awards"
}
read_globals = {

View File

@ -1,4 +1,3 @@
name = bale
description = A bale of hay (wheat)
depends = farming
optional_depends =

View File

@ -1,6 +1,6 @@
function mokapi.cron_clear(cron_time, modname)
if cron_time > 0 then
minetest.after(cron_time, function(cron_time, modname)
minetest.after(cron_time, function()
mokapi.cron_clear_mobs(cron_time, modname)
end, cron_time, modname)
end

View File

@ -1,5 +1,3 @@
name = mokapi
description = A high level API for mobkit
depends = mobkit
optional_depends =
version =

View File

@ -39,3 +39,6 @@ assert(loadfile(modpath .. "/api/api_bottled.lua"))(modpath, S)
assert(loadfile(modpath .. "/api/api_colors.lua"))()
assert(loadfile(modpath .. "/api/api_sell_buy.lua"))(S)
assert(loadfile(modpath .. "/api/api_lifetime.lua"))()
assert(loadfile(modpath .. "/api/api_back_home.lua"))()
assert(loadfile(modpath .. "/api/api_on_deactivate.lua"))()

View File

@ -0,0 +1,40 @@
function petz.back_home(self)
local pos = self.object:get_pos()
local home_pos = self.home_pos
if not home_pos then
return
end
local distance = vector.distance(pos, home_pos)
if distance <= petz.settings["back_home_distance"] then
return
end
local node = minetest.get_node_or_nil(home_pos)
local map_loaded
if not node then
-- Load the map at pos and try again
--minetest.chat_send_all("manip")
minetest.get_voxel_manip():read_from_map(home_pos, home_pos)
node = minetest.get_node(pos)
map_loaded = true
end
if not node then
return
end
if node.name == "air" then
--minetest.chat_send_all("test")
local forceload
if map_loaded then
forceload = minetest.forceload_block(home_pos)
--minetest.chat_send_all("FORCELOAD")
if not forceload then
--minetest.chat_send_all("NO FORCELOAD")
return
end
end
--minetest.chat_send_all("test2")
self.object:set_pos(home_pos)
if map_loaded then
minetest.forceload_free_block(pos)
end
end
end

View File

@ -6,9 +6,8 @@ local S = ...
petz.create_pet = function(placer, itemstack, pet_name, pos)
local meta = itemstack:get_meta()
local meta_table = meta:to_table()
local sdata = minetest.serialize(meta_table)
local mob = minetest.add_entity(pos, pet_name, sdata)
local staticdata = meta:get_string("staticdata")
local mob = minetest.add_entity(pos, pet_name, staticdata)
local self = mob:get_luaentity()
if self.is_wild == false and not(self.owner) then --not monster and not owner
mokapi.set_owner(self, placer:get_player_name()) --set owner
@ -79,32 +78,18 @@ petz.check_capture_items = function(self, wielded_item_name, clicker, check_inv_
end
petz.capture = function(self, clicker, put_in_inventory)
self.captured = mobkit.remember(self, "captured", true) --IMPORTANT! mark as captured
local new_stack = ItemStack(self.name .. "_set") -- add special mob egg with all mob information
--Save the staticdata into the ItemStack-->
local stack_meta = new_stack:get_meta()
--local sett ="---TABLE---: "
--local sett = ""
--local i = 0
for key, value in pairs(self) do
local what_type = type(value)
if what_type ~= "function" and what_type ~= "nil" and what_type ~= "userdata" then
if what_type == "boolean" or what_type == "number" then
value = tostring(value)
elseif what_type == "table" then
if key == "saddlebag_inventory" or key == "genes" or key == "father_genes" or key == "father_veloc_stats" then --only this tables to save serialized
value = minetest.serialize(value)
--minetest.chat_send_player("singleplayer", value)
end
end
stack_meta:set_string(key, value)
--i = i + 1
--sett= sett .. ", ".. tostring(key).." : ".. tostring(self[key])
end
end
--minetest.chat_send_player("singleplayer", sett)
--minetest.chat_send_player("singleplayer", "status="..tostring(self.status))
stack_meta:set_string("captured", "true") --IMPORTANT! mark as captured
--minetest.chat_send_player("singleplayer", tostring(i))
--Info text stuff:
local ent = self.object:get_luaentity()
local staticdata = ent:get_staticdata(self)
stack_meta:set_string("staticdata", staticdata)
--Info text stuff for the ItemStack
local info_text = ""
if not(petz.str_is_empty(self.tag)) then
info_text = info_text.."\n"..S("Name")..": "..self.tag

View File

@ -50,7 +50,7 @@ petz.drop_dreamcatcher = function(self)
end
petz.dreamcatcher_save_metadata = function(self)
if self.tag == "" or not(self.owner) then
if not(self.dreamcatcher) or self.tag == "" or not(self.owner) then
return
end
local item_list_table = petz.tamed_by_owner[self.owner]

View File

@ -1,23 +1,33 @@
local S = ...
petz.create_form = function(player_name, context)
local _context = {}
minetest.register_on_leaveplayer(function(player)
_context[player:get_player_name()] = nil
end)
local function create_context(player_name, tab_id)
_context[player_name] = {}
_context[player_name].tab_id = tab_id
end
petz.create_form = function(player_name, buy)
local pet = petz.pet[player_name]
local form_size = {w = 4, h = 3}
local buttonexit_pos = {x = 1, y = 6}
local hungrystuff_pos = {x= 0, y = 0}
local form_title = ""
local tamagochi_form_stuff = ''
local hungrystuff_pos
local form_title
local tamagochi_form_stuff
local affinity_stuff = ''
local form_orders = ''
local more_form_orders = ''
local tab_form = ''
local final_form = ''
if not context then
context = {}
context.tab_id = 1
if not _context[player_name] then
create_context(player_name, 1)
end
local tab_id = _context[player_name].tab_id
local pet_icon = "petz_spawnegg_"..pet.type..".png"
if context.tab_id == 1 and not(context.buy) then
if tab_id == 1 and not(buy) then
local pet_image_icon = "image[0.375,0.375;1,1;"..pet_icon.."]"
if pet.affinity == nil then
pet.affinity = 0
@ -41,8 +51,8 @@ petz.create_form = function(player_name, context)
"label[1.375,3;".. form_title .."]"..
"image_button[".. (hungrystuff_pos.x+0.5) ..",".. (hungrystuff_pos.y +0.5)..";1,1;petz_pet_bowl_inv.png;btn_bowl;]"..
affinity_stuff
local hungry_label = ""
local health_label = S("Health").." = "..tostring(pet.hp)
local hungry_label
if pet.fed == false then
hungry_label = S("Hungry")
else
@ -72,15 +82,15 @@ petz.create_form = function(player_name, context)
"checkbox[3.5,1.75;btn_muted;"..S("Muted")..";"..petz.vartostring(pet.muted).."]"..
"checkbox[3.5,2.25;btn_show_tag;"..S("Show tag")..";"..petz.vartostring(pet.show_tag).."]"
end
local gender
if pet.is_male == true then
gender = S("Male")
else
gender = S("Female")
end
tamagochi_form_stuff = tamagochi_form_stuff..
"label[3,0.875;"..gender.."]"
if pet.breed == true then --Show the Gender
local gender = ''
if pet.is_male == true then
gender = S("Male")
else
gender = S("Female")
end
tamagochi_form_stuff = tamagochi_form_stuff..
"label[3,0.875;"..gender.."]"
local pregnant_icon_x
local pregnant_icon_y
local pregnant_text_x
@ -109,7 +119,7 @@ petz.create_form = function(player_name, context)
"label["..(pregnant_text_x+0.375)..","..(pregnant_text_y+1)..";"..S("Pregnant").." ("..tostring(pregnant_remain_time).."s)]"
elseif pet.is_male == false and pet.pregnant_count and pet.pregnant_count <= 0 then
tamagochi_form_stuff = tamagochi_form_stuff..
"label["..(pregnant_icon_x+0.5)..","..(infertile_text_y+1)..";"..S("Infertile").."]"
"label["..(infertile_text_x+0.5)..","..(infertile_text_y+1)..";"..S("Infertile").."]"
end
if pet.is_baby == true then
local growth_remain_time = petz.round(petz.settings.growth_time - pet.growth_time)
@ -159,7 +169,7 @@ petz.create_form = function(player_name, context)
form_orders = form_orders .. "button_exit[3.375,5.5;2,1;btn_guard;"..S("Guard").."]"
end
tab_form = tamagochi_form_stuff.. form_orders
elseif context.tab_id == 1 and context.buy then
elseif tab_id == 1 and buy then
form_size.w = form_size.w + 1
form_size.h = form_size.h + 2
buttonexit_pos.x = buttonexit_pos.x + 1
@ -175,7 +185,7 @@ petz.create_form = function(player_name, context)
"label[2,2.5;"..tostring(item_amount).."]"..
"style_type[button_exit;bgcolor=#333600;textcolor=white]"..
"button_exit[2,3.25;2,1;btn_buy;"..S("Buy").."]"
elseif context.tab_id == 2 and not(context.buy) then
elseif tab_id == 2 and not(buy) then
form_size.w = form_size.w + 1
form_size.h = form_size.h + 2
buttonexit_pos.y = buttonexit_pos.y - 2
@ -188,7 +198,20 @@ petz.create_form = function(player_name, context)
tab_form = tab_form .. "image[2,0.375;1,1;petz_lifetime.png]" .. "label[3,0.75;"..S("Lifetime").."]".."label[3,1;"..tostring(pet.lifetime).."]"
end
end
elseif context.tab_id == 3 and petz.settings.selling and not(context.buy) then
elseif (tab_id == 3 and not(buy) and pet.dreamcatcher) then
form_size.w = form_size.w + 2
form_size.h = form_size.h + 1
buttonexit_pos.y = buttonexit_pos.y - 3
tab_form = tab_form ..
"checkbox[0.25,1.5;btn_back_home;"..S("Automatic Go back home")..";"..petz.vartostring(pet.back_home).."]"..
"label[1.3,0.75;<< "..S("Click to set the home").."]"..
"image_button_exit[0.25,0.25;1,1;petz_kennel.png;btn_set_home;"..S("Set").."\n"..S("Home").."]"
if pet.home_pos then
tab_form = tab_form ..
"label[0.25,2.0;"..S("Home Pos")..": x="..tostring(petz.truncate(pet.home_pos.x,1))
..", y="..petz.truncate(pet.home_pos.y,1)..", z="..petz.truncate(pet.home_pos.z,1).."]"
end
elseif (tab_id ==3 or tab_id ==4) and petz.settings.selling and not(buy) then
form_size.w = form_size.w + 1
form_size.h = form_size.h + 2
buttonexit_pos.y = buttonexit_pos.y - 2
@ -219,20 +242,24 @@ petz.create_form = function(player_name, context)
local tab_main = S("Main")
local tab_other = S("Other")
local tab_shop = S("Shop")
local tab_home = S("Home")
local tab_header
if context.buy then
if buy then
tab_header = tab_shop
else
tab_header =tab_main..","..tab_other
tab_header = tab_main..","..tab_other
if pet.dreamcatcher then
tab_header = tab_header..","..tab_home
end
if not(minetest.is_singleplayer()) then
tab_header = tab_header..","..tab_shop
end
end
--minetest.chat_send_player("singleplayer", tab_header)
final_form =
local final_form =
"size["..(form_size.w+0.875)..","..(form_size.h+1)..";]"..
"real_coordinates[true]"..
"tabheader[0,0;tabheader;"..tab_header..";"..tostring(context.tab_id)..";true;false]"..
"tabheader[0,0;tabheader;"..tab_header..";"..tostring(tab_id)..";true;false]"..
tab_form..
"style_type[button_exit;bgcolor=#006699;textcolor=white]"..
"button_exit["..(buttonexit_pos.x+0.5)..","..(buttonexit_pos.y+0.75)..";1,1;btn_close;"..S("Close").."]"
@ -248,9 +275,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.tabheader then
local tab_id = tonumber(fields.tabheader)
if tab_id > 0 then
local context = {}
context.tab_id = tab_id
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, context))
create_context(player_name, tab_id)
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, false))
end
return
end
@ -271,8 +297,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
mobkit.clear_queue_low(pet)
mobkit.clear_queue_high(pet)
pet.status = nil
mobkit.hq_fly(pet, 0)
minetest.after(2.5, function(pet)
petz.hq_fly(pet, 0)
minetest.after(2.5, function()
if mobkit.is_alive(pet) then
mobkit.clear_queue_low(pet)
pet.object:set_acceleration({ x = 0, y = 0, z = 0 })
@ -290,7 +316,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
pet.object:set_attach(player, "Arm_Left", shoulder_pos, {x=0, y=0, z=180})
pet.object:set_properties({physical = false,})
minetest.after(120.0, function(pet)
minetest.after(120.0, function()
if mobkit.is_alive(pet) then
pet.object:set_detach()
pet.object:set_properties({physical = true,})
@ -339,6 +365,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
pet.exchange_item_amount = mobkit.remember(pet, "exchange_item_amount", mokapi.delimit_number( tonumber(fields.fld_exchange_item_amount), {min=1, max=99}) or 1)
elseif fields.btn_buy then
petz.buy(pet, player)
elseif fields.btn_back_home then
pet.back_home= mobkit.remember(pet, "back_home", minetest.is_yes(fields.btn_back_home))
elseif fields.btn_set_home then
pet.home_pos= mobkit.remember(pet, "home_pos", pet.object:get_pos())
create_context(player_name, 3)
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, false))
end
if fields.ipt_name then
pet.tag = minetest.formspec_escape(string.sub(fields.ipt_name, 1 , 12))
@ -350,8 +382,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
petz.update_nametag(pet)
_context[player_name] = nil
return true
else
_context[player_name] = nil
return false
end
end)
@ -419,14 +453,13 @@ petz.create_food_form = function(self)
items_desc = items_desc .. ", "
end
end
local formspec = ""
local form_size = {w= 3, h= 3}
local button_exit = {x= 1, y= 2}
if self.breed == true then
form_size.h = form_size.h + 1
button_exit.y = button_exit.y + 1
end
formspec =
local formspec =
"size["..form_size.w..","..form_size.h.."]"..
"image[0,0;1,1;petz_spawnegg_"..self.type..".png]"..
"label[1,0;"..S("Food").."]"..
@ -450,7 +483,6 @@ petz.create_food_form = function(self)
end
petz.create_affinity_form = function(self)
local formspec = ""
local form_size = {w= 3, h= 4}
local button_exit = {x= 1, y= 3}
local feed_status, feed_status_color
@ -469,7 +501,7 @@ petz.create_affinity_form = function(self)
brushing_status = S("Not brushed")..": " .. tostring(petz.calculate_affinity_change(-petz.settings.tamagochi_brush_rate))
brushing_status_color = petz.colors["red"]
end
formspec =
local formspec =
"size["..form_size.w..","..form_size.h.."]"..
"image[0,0;1,1;petz_affinity_heart.png]"..
"label[1,0;"..S("Affinity").."]"..
@ -487,7 +519,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local player_name = player:get_player_name()
local pet = petz.pet[player_name]
if pet and (mobkit.is_alive(pet)) then
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, context))
create_context(player_name, 1)
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, false))
end
return true
end)
@ -517,9 +550,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
petz.abandon_pet(pet, msg)
end
else
local context = {}
context.tab_id = 2
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, context))
create_context(player_name, 2)
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, false))
end
return true
end)

View File

@ -6,11 +6,15 @@ petz.dyn_prop = {
accel = {type= "int", default = 1},
affinity = {type= "int", default = 100},
anthill_founded = {type= "boolean", default = false},
back_home = {type= "boolean", default = false},
beaver_oil_applied = {type= "boolean", default = false},
behive = {type= "pos", default = false},
behive = {type= "pos", default = nil},
brushed = {type= "boolean", default = false},
captured = {type= "boolean", default = false},
child = {type= "boolean", default = false},
colorized = {type= "string", default = nil},
convert = {type= "string", default = nil},
convert_to = {type= "string", default = nil},
convert_count = {type= "int", default = 5},
dreamcatcher = {type= "boolean", default = false},
dead = {type= "boolean", default = false},
@ -31,9 +35,10 @@ petz.dyn_prop = {
genes = {type= "table", default = {}},
growth_time = {type= "int", default = 0},
herding = {type= "boolean", default = false},
home_pos = {type= "table", default = nil},
horseshoes = {type= "int", default = 0},
is_baby = {type= "boolean", default = false},
is_male = {type= "boolean", default = false},
is_male = {type= "boolean", default = nil},
is_pregnant = {type= "boolean", default = false},
is_rut = {type= "boolean", default = false},
lashed = {type= "boolean", default = false},
@ -48,14 +53,13 @@ petz.dyn_prop = {
pregnant_time = {type= "int", default = 0},
saddle = {type= "boolean", default = false},
saddlebag = {type= "boolean", default = false},
saddlebag_inventory = {type= "table", default = nil},
set_vars = {type= "boolean", default = false},
saddlebag_inventory = {type= "table", default = {}},
shaved = {type= "boolean", default = false},
show_tag = {type= "boolean", default = false},
sleep_start_time = {type= "int", default = nil},
sleep_end_time = {type= "int", default = nil},
square_ball_attached = {type= "boolean", default = false},
status = {type= "string", default = ""},
status = {type= "string", default = nil},
tag = {type= "string", default = ""},
tamed = {type= "boolean", default = false},
--texture_no = {type= "int", default = 1}, --do not use!!! OR MISSING TEXTURE
@ -63,6 +67,29 @@ petz.dyn_prop = {
was_killed_by_player = {type= "boolean", default = false},
}
petz.compose_texture= function(self)
local texture
if self.type == "lamb" then
local shaved_string = ""
if self.shaved == true then
shaved_string = "_shaved"
end
texture = "petz_lamb".. shaved_string .."_"..self.skin_colors[self.texture_no]..".png"
elseif self.is_mountable == true then
if self.saddle then
texture = "petz_"..self.type.."_"..self.skin_colors[self.texture_no]..".png" .. "^petz_"..self.type.."_saddle.png"
else
texture = "petz_"..self.type.."_"..self.skin_colors[self.texture_no]..".png"
end
if self.saddlebag then
texture = texture .. "^petz_"..self.type.."_saddlebag.png"
end
else
texture = self.textures[self.texture_no]
end
return texture
end
petz.cleanup_prop= function(self)
self.warn_attack = false --reset the warn attack
self.driver = nil --no driver
@ -129,11 +156,19 @@ petz.load_vars = function(self)
end
function petz.set_initial_properties(self, staticdata, dtime_s)
--minetest.chat_send_all(staticdata)
local static_data_table = minetest.deserialize(staticdata)
local captured_mob = false
local baby_born = false
--minetest.chat_send_player("singleplayer", staticdata)
if static_data_table and static_data_table["fields"] and static_data_table["fields"]["captured"] then
--TO DELETE IN FUTURE VERSIONS-->
local static_table_name
if static_data_table and static_data_table["memory"] then
static_table_name = "memory"
else
static_table_name = "fields"
end
--<
if static_data_table and static_data_table[static_table_name] and static_data_table[static_table_name]["captured"] then
captured_mob = true
elseif static_data_table and static_data_table["baby_born"] and static_data_table["baby_born"] == true then
baby_born = true
@ -143,56 +178,29 @@ function petz.set_initial_properties(self, staticdata, dtime_s)
--
--dtime_s == 0 differenciates between loaded and new created mobs
if dtime_s == 0 and captured_mob == false then --set some vars
--Mob Specific
--Lamb
if self.type == "lamb" then --set a random color
self.food_count_wool = mobkit.remember(self, "food_count_wool", 0)
self.shaved = mobkit.remember(self, "shaved", false)
elseif self.type == "puppy" then
self.square_ball_attached = mobkit.remember(self, "square_ball_attached", false)
elseif self.is_mountable == true then
--Load default settings ->
for key, value in pairs(petz.dyn_prop) do
self[key] = value["default"]
end
--Define some settings ->
--Set a random gender for all the mobs (not defined in the entity definition)
if self.is_male == nil then
self.is_male = petz.set_random_gender() --set a random gender
end
mobkit.remember(self, "is_male", self.is_male)
if self.is_mountable == true then
if baby_born == false then
self.max_speed_forward= mobkit.remember(self, "max_speed_forward", math.random(2, 4)) --set a random velocity for walk and run
self.max_speed_reverse= mobkit.remember(self, "max_speed_reverse", math.random(1, 2))
self.accel= mobkit.remember(self, "accel", math.random(2, 4))
end
self.driver = mobkit.remember(self, "driver", nil)
--Saddlebag
self.saddle = mobkit.remember(self, "saddle", false)
if self.has_saddlebag == true then
self.saddlebag_ref = nil
self.saddlebag_inventory = mobkit.remember(self, "saddlebag_inventory", {})
end
self.gallop = mobkit.remember(self, "gallop", false)
self.gallop_time = mobkit.remember(self, "gallop_time", 0)
self.gallop_exhausted = mobkit.remember(self, "gallop_exhausted", false)
self.gallop_recover_time = mobkit.remember(self, "gallop_recover_time", petz.settings.gallop_recover_time)
end
if self.parents then
if self.parents then --for chicken only
self.is_baby = mobkit.remember(self, "is_baby", true)
end
if self.type == "pony" then --not in the previopus loop, cos also is mountable
self.horseshoes = mobkit.remember(self, "horseshoes", 0)
end
if self.herd then
self.herding = mobkit.remember(self, "herding", false)
end
--Mobs that can have babies
if self.breed == true then
if self.is_male == nil then
self.is_male = petz.set_random_gender() --set a random gender
end
mobkit.remember(self, "is_male", self.is_male)
self.is_rut = mobkit.remember(self, "is_rut", false)
self.is_pregnant = mobkit.remember(self, "is_pregnant", false)
self.pregnant_time = mobkit.remember(self, "pregnant_time", 0.0)
self.father_genes = mobkit.remember(self, "father_genes", {})
self.father_veloc_stats = mobkit.remember(self, "father_veloc_stats", {})
self.pregnant_count = mobkit.remember(self, "pregnant_count", petz.settings.pregnant_count)
self.is_baby = mobkit.remember(self, "is_baby", false)
self.growth_time = mobkit.remember(self, "growth_time", 0.0)
--Genetics
self.genes = {}
local genes_mutation = false
if self.mutation and (self.mutation > 0) and math.random(1, 200) == 1 then
genes_mutation = true
@ -230,9 +238,6 @@ function petz.set_initial_properties(self, staticdata, dtime_s)
end
mobkit.remember(self, "genes", self.genes)
end
if self.lay_eggs == true then
self.eggs_count = mobkit.remember(self, "eggs_count", 0)
end
--ALL the mobs
--Get a texture
if not(self.texture_no) then
@ -248,38 +253,12 @@ function petz.set_initial_properties(self, staticdata, dtime_s)
self.texture_no = 1
end
end
self.set_vars = mobkit.remember(self, "set_vars", true)
self.tag = mobkit.remember(self, "tag", "")
self.show_tag = mobkit.remember(self, "show_tag", false)
self.tamed = mobkit.remember(self, "tamed", false)
self.owner = mobkit.remember(self, "owner", nil)
self.fed = mobkit.remember(self, "fed", true)
self.for_sale = mobkit.remember(self, "for_sale", false)
self.exchange_item_index = mobkit.remember(self, "exchange_item_index", 1)
self.exchange_item_amount = mobkit.remember(self, "exchange_item_amount", 1)
self.brushed = mobkit.remember(self, "brushed", false)
self.food_count = mobkit.remember(self, "food_count", 0)
self.lifetime = mobkit.remember(self, "lifetime", nil)
self.was_killed_by_player = mobkit.remember(self, "was_killed_by_player", false)
self.dreamcatcher = mobkit.remember(self, "dreamcatcher", false)
self.status = mobkit.remember(self, "status", nil)
self.warn_attack = mobkit.remember(self, "warn_attack", false)
self.colorized = mobkit.remember(self, "colorized", nil)
self.convert = mobkit.remember(self, "convert", nil)
self.muted = mobkit.remember(self, "muted", false)
if petz.settings[self.type.."_convert_count"] then
self.convert_count = mobkit.remember(self, "convert_count", petz.settings[self.type.."_convert_count"])
end
if self.init_tamagochi_timer== true then
petz.init_tamagochi_timer(self)
end
if self.has_affinity == true then
self.affinity = mobkit.remember(self, "affinity", 100)
end
if self.is_wild == true then
self.lashed = mobkit.remember(self, "lashed", false)
self.lashing_count = mobkit.remember(self, "lashing_count", 0)
end
petz.calculate_sleep_times(self) --Sleep behaviour
--
--2. ALREADY EXISTING MOBS
@ -290,58 +269,38 @@ function petz.set_initial_properties(self, staticdata, dtime_s)
--3. CAPTURED MOBS
--
else
self.captured = mobkit.remember(self, "captured", false) --IMPORTANT! mark as not captured
for key, value in pairs(petz.dyn_prop) do
local prop_value
if value["type"] == "string" then
prop_value = static_data_table["fields"][key]
prop_value = static_data_table[static_table_name][key]
elseif value["type"] == "int" then
prop_value = tonumber(static_data_table["fields"][key])
prop_value = tonumber(static_data_table[static_table_name][key])
elseif value["type"] == "boolean" then
prop_value = minetest.is_yes(static_data_table["fields"][key])
prop_value = minetest.is_yes(static_data_table[static_table_name][key])
elseif value["type"] == "table" then
prop_value = minetest.deserialize(static_data_table["fields"][key])
prop_value = minetest.deserialize(static_data_table[static_table_name][key])
elseif value["type"] == "player" then
prop_value = nil
end
self[key] = mobkit.remember(self, key, prop_value) or value["default"]
end
self.texture_no = tonumber(static_data_table["fields"]["texture_no"])
end
--Custom textures
if captured_mob == true or self.breed == true then
local texture
--Mob Specific
--Lamb
if self.type == "lamb" then
local shaved_string = ""
if self.shaved == true then
shaved_string = "_shaved"
end
texture = "petz_lamb".. shaved_string .."_"..self.skin_colors[self.texture_no]..".png"
elseif self.is_mountable == true then
if self.saddle then
texture = "petz_"..self.type.."_"..self.skin_colors[self.texture_no]..".png" .. "^petz_"..self.type.."_saddle.png"
else
texture = "petz_"..self.type.."_"..self.skin_colors[self.texture_no]..".png"
end
if self.saddlebag then
texture = texture .. "^petz_"..self.type.."_saddlebag.png"
end
else
texture = self.textures[self.texture_no]
end
local texture= petz.compose_texture(self) --compose the texture
mobkit.remember(self, "texture_no", self.texture_no)
petz.set_properties(self, {textures = {texture}})
end
if self.type == "bee" and self.queen then --delay to create beehive
minetest.after(math.random(120, 150), function(self)
minetest.after(math.random(120, 150), function()
if mobkit.is_alive(self.object) then
self.create_beehive = mobkit.remember(self, "create_beehive", true)
end
end, self)
elseif self.type == "ant" and self.ant_type == "queen" then
minetest.after(math.random(120, 150), function(self)
minetest.after(math.random(120, 150), function()
if mobkit.is_alive(self.object) then
self.create_anthill = mobkit.remember(self, "create_anthill", true)
end

View File

@ -0,0 +1,3 @@
function petz.on_deactivate(self)
petz.dreamcatcher_save_metadata(self)
end

View File

@ -71,7 +71,7 @@ function petz.on_punch(self, puncher, time_from_last_punch, tool_capabilities, d
self.object:set_properties(self, {textures = {punch_texture}})
minetest.after(0.1, function()
if self then
self.object:set_properties(self, {textures = { self.textures[self.texture_no]}})
self.object:set_properties(self, {textures = { petz.compose_texture(self) }})
end
end)
end

View File

@ -29,7 +29,7 @@ petz.on_rightclick = function(self, clicker)
local wielded_item = clicker:get_wielded_item()
local wielded_item_name = wielded_item:get_name()
local show_form = false
local context = {}
local buy
if ((self.is_pet == true) and is_owner and (self.can_be_brushed == true)) -- If brushing or spread beaver oil
and ((wielded_item_name == "petz:hairbrush") or (wielded_item_name == "petz:beaver_oil")) then
@ -62,7 +62,7 @@ petz.on_rightclick = function(self, clicker)
petz.capture(self, clicker, true)
minetest.chat_send_player("singleplayer", S("Your").." "..S(pet_name).." "..S("has been captured")..".")
elseif self.breed and wielded_item_name == petz.settings[self.type.."_breed"] and not(self.is_baby) then
minetest.chat_send_all("test="..petz.settings[self.type.."_breed"])
--minetest.chat_send_all("test="..petz.settings[self.type.."_breed"])
petz.breed(self, clicker, wielded_item, wielded_item_name)
elseif (wielded_item_name == "petz:dreamcatcher") and (self.tamed == true) and (self.is_pet == true) and is_owner then
petz.put_dreamcatcher(self, clicker, wielded_item, wielded_item_name)
@ -107,17 +107,16 @@ petz.on_rightclick = function(self, clicker)
show_form = true
end
elseif petz.settings.selling and not(minetest.is_singleplayer()) and self.for_sale and self.owner and not(self.owner == player_name) then --Buy Form
context.buy = true
buy = true
show_form = true
else --Else open the Form
if (self.is_pet == true) and ((self.tamed == true) and (self.owner == player_name)) then
context.buy = false
buy = false
show_form = true
end
end
if show_form then
context.tab_id = 1
petz.pet[player_name]= self
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, context))
minetest.show_formspec(player_name, "petz:form_orders", petz.create_form(player_name, buy))
end
end

View File

@ -12,13 +12,16 @@ petz.on_step = function(self, dtime)
if self.gallop == true then
petz.gallop(self, on_step_time)
end
if self.dreamcatcher then
if not(self.on_deactivate) then
petz.dreamcatcher_save_metadata(self)
end
local lifetime = petz.check_lifetime(self)
if lifetime then
petz.lifetime_timer(self, lifetime, on_step_time)
end
if self.dreamcatcher and self.back_home then
petz.back_home(self)
end
--Tamagochi
--Check the hungry
if petz.settings.tamagochi_mode == true and self.owner and self.is_pet and petz.settings.tamagochi_hungry_warning > 0 and not(self.status=="sleep") and petz.settings[self.type.."_follow"] then

View File

@ -1,7 +1,7 @@
petz.ownthing = function(self)
self.status = mobkit.remember(self, "status", nil)
if self.can_fly then
mobkit.hq_wanderfly(self, 0)
petz.hq_wanderfly(self, 0)
elseif self.can_swin and self.isinliquid then
mobkit.hq_aqua_roam(self, 0, self.max_speed)
else
@ -20,7 +20,7 @@ petz.standhere = function(self)
mobkit.clear_queue_high(self)
mobkit.clear_queue_low(self)
if self.can_fly == true then
if mobkit.node_name_in(self, "below") == "air" then
if petz.node_name_in(self, "below") == "air" then
mobkit.animate(self, "fly")
else
mobkit.animate(self, "stand")
@ -51,10 +51,10 @@ petz.follow = function(self, player)
self.status = mobkit.remember(self, "status", "follow")
if self.can_fly then
mobkit.animate(self, "fly")
mobkit.hq_followliquidair(self, 100, player)
petz.hq_followliquidair(self, 100, player)
elseif self.can_swin and self.isinliquid then
mobkit.animate(self, "def")
mobkit.hq_followliquidair(self, 100, player)
petz.hq_followliquidair(self, 100, player)
else
mobkit.hq_follow(self, 100, player)
end
@ -63,8 +63,8 @@ end
petz.alight = function(self)
mobkit.clear_queue_low(self)
mobkit.clear_queue_high(self)
if not(mobkit.node_name_in(self, "below") == "air") then
if not(petz.node_name_in(self, "below") == "air") then
mobkit.animate(self, "fly")
end
mobkit.hq_alight(self, 0)
petz.hq_alight(self, 0)
end

View File

@ -6,8 +6,8 @@ petz.poop = function(self, pos)
if not(petz.settings.poop) or not(self.tamed) or not(self.poop) or self.child == true or petz.is_jumping(self) or not(petz.is_standing(self)) or math.random(1, petz.settings.poop_rate) > 1 then
return
end
local node_name_below = mobkit.node_name_in(self, "below")
local node_name = mobkit.node_name_in(self, "self")
local node_name_below = petz.node_name_in(self, "below")
local node_name = petz.node_name_in(self, "self")
--minetest.chat_send_player("singleplayer", node_name)
if node_name == "air" and node_name_below ~= "air" then
pos.y = pos.y - 0.75

View File

@ -162,7 +162,7 @@ minetest.register_craft({
})
petz.init_convert_to_chrysalis = function(self)
minetest.after(math.random(1200, 1500), function(self)
minetest.after(math.random(1200, 1500), function()
if not(mobkit.is_alive(self)) then
return
end
@ -176,7 +176,7 @@ petz.init_convert_to_chrysalis = function(self)
end
petz.init_lay_eggs = function(self)
minetest.after(math.random(150, 240), function(self)
minetest.after(math.random(150, 240), function()
if not(mobkit.is_alive(self)) then
return
end
@ -184,7 +184,7 @@ petz.init_lay_eggs = function(self)
return
end
petz.alight(self)
minetest.after(10.0, function(self)
minetest.after(10.0, function()
if not(mobkit.is_alive(self)) then
return
end
@ -192,7 +192,7 @@ petz.init_lay_eggs = function(self)
if minetest.get_node(pos) and minetest.get_node(pos).name ~= "air" then
return
end
local node_name = mobkit.node_name_in(self, "below")
local node_name = petz.node_name_in(self, "below")
local spawn_egg = false
if string.sub(petz.settings.silkworm_lay_egg_on_node, 1, 5) == "group" then
local node_group = minetest.get_item_group(node_name, string.sub(petz.settings.silkworm_lay_egg_on_node, 7))

View File

@ -65,12 +65,12 @@ petz.sleep = function(self, prty, force)
mobkit.animate(self, 'sleep')
local texture = self.textures[self.texture_no]
self.object:set_properties(self, {textures = {texture.."^petz_"..self.type.."_sleep.png"}}) --sleeping eyes
mobkit.hq_sleep(self, prty, force)
petz.hq_sleep(self, prty, force)
end
function mobkit.hq_sleep(self, prty, force)
function petz.hq_sleep(self, prty, force)
local timer = 2
local func=function(self)
local func=function()
timer = timer - self.dtime
if timer < 0 then
if not(force) then

View File

@ -187,15 +187,17 @@ petz.spawn_mob = function(spawn_pos, limit_max_mobs, abr, liquidflag)
else
spawn_pos.z = spawn_pos.z - 2
end
--[[
if i > 1 then
local height, liquidflag = mobkit.get_terrain_height(spawn_pos, 32)
if height or (liquidflag and ent.can_swin) then
local node = petz.get_node_below(spawn_pos)
if not(mokapi.item_in_itemlist(node.name, petz.settings[random_mob.."_spawn_nodes"])) then
local height, liquidflag2 = mobkit.get_terrain_height(spawn_pos, 32)
if height or (liquidflag2 and ent.can_swin) then
local node_below = petz.get_node_below(spawn_pos)
if not(mokapi.item_in_itemlist(node_below.name, petz.settings[random_mob.."_spawn_nodes"])) then
spawn = false
end
end
end
]]
if spawn == true then
spawn_pos = petz.pos_to_spawn(random_mob_name, spawn_pos) --recalculate pos.y for bigger mobs
minetest.add_entity(spawn_pos, random_mob_name)
@ -211,7 +213,7 @@ minetest.register_globalstep(function(dtime)
local abr = tonumber(minetest.get_mapgen_setting('active_block_range')) or 3
local radius = abr * 16 --recommended
local interval = petz.settings.spawn_interval
local spawn_pos, liquidflag, cave = mobkit.get_spawn_pos_abr(dtime, interval, radius, petz.settings.spawn_chance, 0.2)
local spawn_pos, liquidflag = mobkit.get_spawn_pos_abr(dtime, interval, radius, petz.settings.spawn_chance, 0.2)
if spawn_pos then
petz.spawn_mob(spawn_pos, true, abr, liquidflag)
end

View File

@ -42,7 +42,7 @@ end
--
petz.timer = function(self)
minetest.after(petz.settings.tamagochi_check_time, function(self)
minetest.after(petz.settings.tamagochi_check_time, function()
if mobkit.is_alive(self) then
if (not(minetest.is_singleplayer())) and (petz.settings.tamagochi_check_if_player_online == true) then
if minetest.player_exists(self.owner) == false then --if pet owner is not online

View File

@ -4,12 +4,12 @@ awards.register_trigger("milk", {
auto_description = { "Do a foo", "Foo @1 times" },
})
minetest.register_on_milk(function()
for _, trigger in pairs(awards.on.milk) do
--minetest.register_on_milk(function()
--for _, trigger in pairs(awards.on.milk) do
if condition then
awards.unlock(trigger)
end
end
end)
--if condition then
--awards.unlock(trigger)
--end
--end
--end)

View File

@ -5,7 +5,6 @@
local modname = "petz"
local modpath = minetest.get_modpath(modname)
local mg_name = minetest.get_mapgen_setting("mg_name")
-- internationalization boilerplate
local S = minetest.get_translator(minetest.get_current_modname())

View File

@ -13,6 +13,7 @@ Anthill Entrance=Entrada do formigueiro
Alight=Posse
A silk bobbin has been created!=Uma bobina de seda foi criada!
Amount=Quantidade
Automatic Go back home=Regresso automático a casa
Bat=Morcego
Beaver Fur=Pele de castor
Beaver Oil=Óleo de castor
@ -34,6 +35,7 @@ Blueberry Muffin=Muffin de mirtilo
Bone=Ossos
Bottle with Moth=Garrafa com traça
Brushed=Escovado
Bunny=Coelhinho
Butterfly=Borboleta
Butterfly Showcase=Exibição de borboletas
Buy=Compre
@ -100,6 +102,8 @@ has starved to death!!!=morreu de fome!!!
Saúde=Abraço
Hen=Galinha
Herding=Pastoreio
Home=Casa
Home Pos=Pos. de casa
Honey=Mel
Honeycomb=Favo de mel
Honey Bottle=Pote de mel
@ -161,16 +165,19 @@ Poop Block=Bloco de cocozinho
Pregnant=Grávida
Pumpkin Hood=Capuz de abóbora
Puppy=Cachorro
Click to set the home=Clique para definir a casa
Prince Crown=A coroa do príncipe
Prince of North Coat=Jaqueta do Príncipe do Norte
Queen Ant=Formiga Rainha
Queen Bee=Abelha Rainha
Rabbit Hide=Couro de coelho
Rat=Rato
Raw Chicken=Frango cru
Raw Ducky=Pato cru
Raw Goat=Caprino cru
Raw Parrot=Papagaio Cru
Raw Porkchop=Costeleta de porco crua
Raw Rabbit=Coelho cru
Roasted Chicken=Frango Assado
Roasted Chicken Legs=Coxas de frango assado
Roasted Ducky=Pato assado
@ -179,6 +186,7 @@ Roasted Goat Meat=Carne assada de caprino
Roasted Lamb Chop=Costeleta de cordeiro assada
Roasted Parrot=Papagaio Assado
Roasted Porkchop=Costeleta de porco assada
Roasted Rabbit=Coelho assado
Rooster=Galo
Saddle=Sela
Saddlebag=Sacos de Sela

View File

@ -13,6 +13,7 @@ Anthill Entrance=Eingang zum Ameisenhügel
Alight=Absteigen
A silk bobbin has been created!=Eine Seidenspule wurde erstellt!
Amount=Amount
Automatic Go back home=Automatisch Nach Hause gehen
Bat=Fledermaus
Beaver Fur=Bieberpelz
Beaver Oil=Bieberöl
@ -34,6 +35,7 @@ Blueberry Muffin=Blaubeermuffin
Bone=Knochen
Bottle with Moth=Flasche mit Motte
Brushed=Gebürstet
Bunny=Kaninchen
Butterfly=Schmetterling
Butterfly Showcase=Schmetterling-Vitrine
Buy=Kaufen
@ -100,6 +102,8 @@ has starved to death!!!=ist verhungert!!!
Health=Gesundheit
Hen=Henne
Herding=Hüten
Home=Zuhause
Home Pos=Ausgangsposition
Honey=Honig
Honeycomb=Honigwabe
Honey Bottle=Honigglas
@ -161,10 +165,12 @@ Poop Block=Mistblock
Pregnant=Trächtig
Pumpkin Hood=Kürbishaube
Puppy=Hündchen
Click to set the home=Klicken Sie auf, um die Heimat einzustellen.
Prince Crown=Prinzenkrone
Prince of North Coat=Umhang des Prinz des Nordens
Queen Ant=Ameisenkönigin
Queen Bee=Bienenkönigin
Rabbit Hide=Kaninchenfell
Rat=Ratte
Raw Chicken=Rohes Hühnchen
Raw Ducky=Rohes Entlein
@ -172,6 +178,7 @@ Raw Goat=Rohes Ziege
Raw Parrot=Roher Papagei
Raw Porkchop=Rohes Schweinekotelett
Roasted Chicken=Gebratenes Hühnchen
Raw Rabbit=Rohe Kaninchen
Roasted Chicken Legs=Gebratene Hühnchenkeule
Roasted Ducky=Gebratenes Entlein
Roasted Frog Leg=Gebratener Froschschenkel
@ -179,6 +186,7 @@ Roasted Goat Meat=Gebratenes Ziegenfleisch
Roasted Lamb Chop=Gebratene Lammkeule
Roasted Parrot=Gebratener Papagei
Roasted Porkchop=Gebratenes Schweinekotelett
Roasted Rabbit=Gebratenes Kaninchen
Rooster=Hahn
Saddle=Sattel
Saddlebag=Satteltasche

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