Tweak some textures, new chest texture
[oweals/minetest_game.git] / mods / default / trees.lua
1 --
2 -- Grow trees
3 --
4
5 local random = math.random
6
7 local function can_grow(pos)
8         local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
9         if not node_under then
10                 return false
11         end
12         local name_under = node_under.name
13         local is_soil = minetest.get_item_group(name_under, "soil")
14         if is_soil == 0 then
15                 return false
16         end
17         return true
18 end
19
20 minetest.register_abm({
21         nodenames = {"default:sapling"},
22         interval = 10,
23         chance = 50,
24         action = function(pos, node)
25                 if not can_grow(pos) then
26                         return
27                 end
28
29                 minetest.log("action", "A sapling grows into a tree at "..minetest.pos_to_string(pos))
30                 default.grow_tree(pos, random(1, 4) == 1)
31         end
32 })
33
34 minetest.register_abm({
35         nodenames = {"default:junglesapling"},
36         interval = 10,
37         chance = 50,
38         action = function(pos, node)
39                 if not can_grow(pos) then
40                         return
41                 end
42
43                 minetest.log("action", "A jungle sapling grows into a tree at "..
44                                 minetest.pos_to_string(pos))
45                 default.grow_jungletree(pos)
46         end
47 })
48
49
50 local c_air = minetest.get_content_id("air")
51 local c_apple = minetest.get_content_id("default:apple")
52
53 local function add_trunk_and_leaves(data, a, pos, tree_cid, leaves_cid,
54                 height, size, iters, is_apple_tree)
55         local x, y, z = pos.x, pos.y, pos.z
56
57         -- Trunk
58         for y_dist = 0, height - 1 do
59                 local vi = a:index(x, y + y_dist, z)
60                 if y_dist == 0 or data[vi] == c_air or data[vi] == leaves_cid then
61                         data[vi] = tree_cid
62                 end
63         end
64
65         -- Force leaves near the trunk
66         for z_dist = -1, 1 do
67         for y_dist = -size, 1 do
68                 local vi = a:index(x - 1, y + height + y_dist, z + z_dist)
69                 for x_dist = -1, 1 do
70                         if data[vi] == c_air then
71                                 if is_apple_tree and random(1, 8) == 1 then
72                                         data[vi] = c_apple
73                                 else
74                                         data[vi] = leaves_cid
75                                 end
76                         end
77                         vi = vi + 1
78                 end
79         end
80         end
81
82         -- Randomly add leaves in 2x2x2 clusters.
83         for i = 1, iters do
84                 local clust_x = x + random(-size, size - 1)
85                 local clust_y = y + height + random(-size, 0)
86                 local clust_z = z + random(-size, size - 1)
87
88                 for xi = 0, 1 do
89                 for yi = 0, 1 do
90                 for zi = 0, 1 do
91                         local vi = a:index(clust_x + xi, clust_y + yi, clust_z + zi)
92                         if data[vi] == c_air then
93                                 if is_apple_tree and random(1, 8) == 1 then
94                                         data[vi] = c_apple
95                                 else
96                                         data[vi] = leaves_cid
97                                 end
98                         end
99                 end
100                 end
101                 end
102         end
103 end
104
105
106 local c_tree = minetest.get_content_id("default:tree")
107 local c_leaves = minetest.get_content_id("default:leaves")
108
109 function default.grow_tree(pos, is_apple_tree, bad)
110         --[[
111                 NOTE: Tree-placing code is currently duplicated in the engine
112                 and in games that have saplings; both are deprecated but not
113                 replaced yet
114         --]]
115         if bad then
116                 error("Deprecated use of default.grow_tree")
117         end
118
119         local x, y, z = pos.x, pos.y, pos.z
120         local height = random(4, 5)
121
122         local vm = minetest.get_voxel_manip()
123         local minp, maxp = vm:read_from_map(
124                         {x = pos.x - 2, y = pos.y, z = pos.z - 2},
125                         {x = pos.x + 2, y = pos.y + height + 1, z = pos.z + 2}
126         )
127         local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
128         local data = vm:get_data()
129
130         add_trunk_and_leaves(data, a, pos, c_tree, c_leaves, height, 2, 8, is_apple_tree)
131
132         vm:set_data(data)
133         vm:write_to_map()
134         vm:update_map()
135 end
136
137 local c_jungletree = minetest.get_content_id("default:jungletree")
138 local c_jungleleaves = minetest.get_content_id("default:jungleleaves")
139
140 function default.grow_jungletree(pos, bad)
141         --[[
142                 NOTE: Tree-placing code is currently duplicated in the engine
143                 and in games that have saplings; both are deprecated but not
144                 replaced yet
145         --]]
146         if bad then
147                 error("Deprecated use of default.grow_jungletree")
148         end
149
150         local x, y, z = pos.x, pos.y, pos.z
151         local height = random(8, 12)
152
153         local vm = minetest.get_voxel_manip()
154         local minp, maxp = vm:read_from_map(
155                         {x = pos.x - 3, y = pos.y - 1,  z = pos.z - 3},
156                         {x = pos.x + 3, y = pos.y + height + 1, z = pos.z + 3})
157         local a = VoxelArea:new({MinEdge = minp, MaxEdge = maxp})
158         local data = vm:get_data()
159
160         add_trunk_and_leaves(data, a, pos, c_jungletree, c_jungleleaves, height, 3, 30, false)
161
162         -- Roots
163         for z_dist = -1, 1 do
164                 local vi_1 = a:index(x - 1, y - 1, z + z_dist)
165                 local vi_2 = a:index(x - 1, y,     z + z_dist)
166                 for x_dist = -1, 1 do
167                         if random(1, 3) >= 2 then
168                                 if data[vi_1] == c_air then
169                                         data[vi_1] = c_jungletree
170                                 elseif data[vi_2] == c_air then
171                                         data[vi_2] = c_jungletree
172                                 end
173                         end
174                         vi_1 = vi_1 + 1
175                         vi_2 = vi_2 + 1
176                 end
177         end
178
179         vm:set_data(data)
180         vm:write_to_map()
181         vm:update_map()
182 end
183