/*
-Minetest-c55
-Copyright (C) 2010-2012 celeron55, Perttu Ahola <celeron55@gmail.com>,
- 2012 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>,
+ 2012-2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <irr_v3d.h>
+#include "irr_v3d.h"
#include <stack>
-#include "noise.h"
+#include "util/pointer.h"
+#include "util/numeric.h"
+#include "util/mathconstants.h"
#include "map.h"
#include "environment.h"
#include "nodedef.h"
{
void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
- bool is_apple_tree, INodeDefManager *ndef)
+ bool is_apple_tree, INodeDefManager *ndef, int seed)
{
+ /*
+ NOTE: Tree-placing code is currently duplicated in the engine
+ and in games that have saplings; both are deprecated but not
+ replaced yet
+ */
MapNode treenode(ndef->getId("mapgen_tree"));
MapNode leavesnode(ndef->getId("mapgen_leaves"));
MapNode applenode(ndef->getId("mapgen_apple"));
- s16 trunk_h = myrand_range(4, 5);
+ PseudoRandom pr(seed);
+ s16 trunk_h = pr.range(4, 5);
v3s16 p1 = p0;
for(s16 ii=0; ii<trunk_h; ii++)
{
s16 d = 1;
v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
);
for(s16 z=0; z<=d; z++)
continue;
u32 i = leaves_a.index(x,y,z);
if(leaves_d[i] == 1) {
- bool is_apple = myrand_range(0,99) < 10;
+ bool is_apple = pr.range(0,99) < 10;
if(is_apple_tree && is_apple) {
vmanip.m_data[vi] = applenode;
} else {
}
// L-System tree LUA spawner
-void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
+void spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition)
{
ServerMap *map = &env->getServerMap();
- core::map<v3s16, MapBlock*> modified_blocks;
+ std::map<v3s16, MapBlock*> modified_blocks;
ManualMapVoxelManipulator vmanip(map);
v3s16 tree_blockp = getNodeBlockPos(p0);
- vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
+ vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,3,1));
make_ltree (vmanip, p0, ndef, tree_definition);
vmanip.blitBackAll(&modified_blocks);
// update lighting
- core::map<v3s16, MapBlock*> lighting_modified_blocks;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
- {
- lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
- }
+ std::map<v3s16, MapBlock*> lighting_modified_blocks;
+ lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
map->updateLighting(lighting_modified_blocks, modified_blocks);
// Send a MEET_OTHER event
MapEditEvent event;
event.type = MEET_OTHER;
- for(core::map<v3s16, MapBlock*>::Iterator
- i = modified_blocks.getIterator();
- i.atEnd() == false; i++)
+ for(std::map<v3s16, MapBlock*>::iterator
+ i = modified_blocks.begin();
+ i != modified_blocks.end(); ++i)
{
- v3s16 p = i.getNode()->getKey();
- event.modified_blocks.insert(p, true);
+ event.modified_blocks.insert(i->first);
}
map->dispatchEvent(&event);
}
{
MapNode dirtnode(ndef->getId("mapgen_dirt"));
+ PseudoRandom ps(tree_definition.seed+14002);
// chance of inserting abcd rules
double prop_a = 9;
double prop_b = 8;
//randomize tree growth level, minimum=2
s16 iterations = tree_definition.iterations;
if (tree_definition.iterations_random_level>0)
- iterations -= myrand_range(0,tree_definition.iterations_random_level);
+ iterations -= ps.range(0,tree_definition.iterations_random_level);
if (iterations<2)
iterations=2;
s16 MAX_ANGLE_OFFSET = 5;
double angle_in_radians = (double)tree_definition.angle*M_PI/180;
- double angleOffset_in_radians = (s16)(myrand_range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
+ double angleOffset_in_radians = (s16)(ps.range(0,1)%MAX_ANGLE_OFFSET)*M_PI/180;
//initialize rotation matrix, position and stacks for branches
core::matrix4 rotation;
- rotation=setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
- v3f position = v3f(0,0,0);
+ rotation = setRotationAxisRadians(rotation, M_PI/2,v3f(0,0,1));
+ v3f position;
+ position.X = p0.X;
+ position.Y = p0.Y;
+ position.Z = p0.Z;
std::stack <core::matrix4> stack_orientation;
std::stack <v3f> stack_position;
temp+=tree_definition.rules_d;
break;
case 'a':
- if (prop_a >= myrand_range(1,10))
+ if (prop_a >= ps.range(1,10))
temp+=tree_definition.rules_a;
break;
case 'b':
- if (prop_b >= myrand_range(1,10))
+ if (prop_b >= ps.range(1,10))
temp+=tree_definition.rules_b;
break;
case 'c':
- if (prop_c >= myrand_range(1,10))
+ if (prop_c >= ps.range(1,10))
temp+=tree_definition.rules_c;
break;
case 'd':
- if (prop_d >= myrand_range(1,10))
+ if (prop_d >= ps.range(1,10))
temp+=tree_definition.rules_d;
break;
default:
}
//make sure tree is not floating in the air
- if (tree_definition.thin_trunks == false)
+ if (tree_definition.trunk_type == "double")
+ {
+ tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z+1),dirtnode);
+ }
+ if (tree_definition.trunk_type == "crossed")
{
- make_tree_node_placement(vmanip,v3f(p0.X+position.X+1,p0.Y+position.Y-1,p0.Z+position.Z),dirtnode);
- make_tree_node_placement(vmanip,v3f(p0.X+position.X-1,p0.Y+position.Y-1,p0.Z+position.Z),dirtnode);
- make_tree_node_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y-1,p0.Z+position.Z+1),dirtnode);
- make_tree_node_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y-1,p0.Z+position.Z-1),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X+1,position.Y-1,position.Z),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X-1,position.Y-1,position.Z),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z+1),dirtnode);
+ tree_node_placement(vmanip,v3f(position.X,position.Y-1,position.Z-1),dirtnode);
}
/* build tree out of generated axiom
Key for Special L-System Symbols used in Axioms
- G - move forward one unit with the pin down
- F - move forward one unit with the pin up
+ G - move forward one unit with the pen up
+ F - move forward one unit with the pen down drawing trunks and branches
+ f - move forward one unit with the pen down drawing leaves (100% chance)
+ T - move forward one unit with the pen down drawing trunks only
+ R - move forward one unit with the pen down placing fruit
A - replace with rules set A
B - replace with rules set B
C - replace with rules set C
switch (axiom_char)
{
case 'G':
- dir = v3f(-1,0,0);
+ dir = v3f(1,0,0);
+ dir = transposeMatrix(rotation,dir);
+ position+=dir;
+ break;
+ case 'T':
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
+ if (tree_definition.trunk_type == "double" && !tree_definition.thin_branches)
+ {
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
+ }
+ if (tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches)
+ {
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
+ }
+ dir = v3f(1,0,0);
dir = transposeMatrix(rotation,dir);
position+=dir;
break;
case 'F':
- make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
- if (tree_definition.thin_trunks == false)
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
+ if ((stack_orientation.empty() && tree_definition.trunk_type == "double") ||
+ (!stack_orientation.empty() && tree_definition.trunk_type == "double" && !tree_definition.thin_branches))
{
- make_tree_trunk_placement(vmanip,v3f(p0.X+position.X+1,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
- make_tree_trunk_placement(vmanip,v3f(p0.X+position.X-1,p0.Y+position.Y,p0.Z+position.Z),tree_definition);
- make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z+1),tree_definition);
- make_tree_trunk_placement(vmanip,v3f(p0.X+position.X,p0.Y+position.Y,p0.Z+position.Z-1),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z+1),tree_definition);
+ }
+ if ((stack_orientation.empty() && tree_definition.trunk_type == "crossed") ||
+ (!stack_orientation.empty() && tree_definition.trunk_type == "crossed" && !tree_definition.thin_branches))
+ {
+ tree_trunk_placement(vmanip,v3f(position.X+1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X-1,position.Y,position.Z),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z+1),tree_definition);
+ tree_trunk_placement(vmanip,v3f(position.X,position.Y,position.Z-1),tree_definition);
}
if (stack_orientation.empty() == false)
{
s16 size = 1;
- for(x=-size; x<size+1; x++)
- for(y=-size; y<size+1; y++)
- for(z=-size; z<size+1; z++)
- if (abs(x) == size and abs(y) == size and abs(z) == size)
+ for(x=-size; x<=size; x++)
+ for(y=-size; y<=size; y++)
+ for(z=-size; z<=size; z++)
+ if (abs(x) == size && abs(y) == size && abs(z) == size)
{
- make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x+1,p0.Y+position.Y+y,p0.Z+position.Z+z),tree_definition);
- make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x-1,p0.Y+position.Y+y,p0.Z+position.Z+z),tree_definition);
- make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x,p0.Y+position.Y+y,p0.Z+position.Z+z+1),tree_definition);
- make_tree_leaves_placement(vmanip,v3f(p0.X+position.X+x,p0.Y+position.Y+y,p0.Z+position.Z+z-1),tree_definition);
+ tree_leaves_placement(vmanip,v3f(position.X+x+1,position.Y+y,position.Z+z),ps.next(), tree_definition);
+ tree_leaves_placement(vmanip,v3f(position.X+x-1,position.Y+y,position.Z+z),ps.next(), tree_definition);
+ tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z+1),ps.next(), tree_definition);
+ tree_leaves_placement(vmanip,v3f(position.X+x,position.Y+y,position.Z+z-1),ps.next(), tree_definition);
}
}
dir = v3f(1,0,0);
dir = transposeMatrix(rotation,dir);
position+=dir;
break;
- // turtle commands
+ case 'f':
+ tree_single_leaves_placement(vmanip,v3f(position.X,position.Y,position.Z),ps.next() ,tree_definition);
+ dir = v3f(1,0,0);
+ dir = transposeMatrix(rotation,dir);
+ position+=dir;
+ break;
+ case 'R':
+ tree_fruit_placement(vmanip,v3f(position.X,position.Y,position.Z),tree_definition);
+ dir = v3f(1,0,0);
+ dir = transposeMatrix(rotation,dir);
+ position+=dir;
+ break;
+
+ // turtle orientation commands
case '[':
stack_orientation.push(rotation);
stack_position.push(position);
}
}
-void make_tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
MapNode node)
{
- v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
if(vmanip.m_area.contains(p1) == false)
return;
u32 vi = vmanip.m_area.index(p1);
vmanip.m_data[vmanip.m_area.index(p1)] = node;
}
-void make_tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+void tree_trunk_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
TreeDef &tree_definition)
{
- v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
if(vmanip.m_area.contains(p1) == false)
return;
u32 vi = vmanip.m_area.index(p1);
vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.trunknode;
}
-void make_tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
- TreeDef &tree_definition)
+void tree_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ PseudoRandom ps ,TreeDef &tree_definition)
{
- v3s16 p1 = v3s16(round(p0.X),round(p0.Y),round(p0.Z));
+ MapNode leavesnode=tree_definition.leavesnode;
+ if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
+ leavesnode=tree_definition.leaves2node;
+ v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
if(vmanip.m_area.contains(p1) == false)
return;
u32 vi = vmanip.m_area.index(p1);
if(vmanip.m_data[vi].getContent() != CONTENT_AIR
&& vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
- return;
- if (tree_definition.fruit_tree)
+ return;
+ if (tree_definition.fruit_chance>0)
{
- if (myrand_range(1,100) > 90+tree_definition.iterations)
+ if (ps.range(1,100) > 100-tree_definition.fruit_chance)
vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
else
- vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.leavesnode;
+ vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
}
- else if (myrand_range(1,100) > 20)
- vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.leavesnode;
+ else if (ps.range(1,100) > 20)
+ vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
+}
+
+void tree_single_leaves_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ PseudoRandom ps, TreeDef &tree_definition)
+{
+ MapNode leavesnode=tree_definition.leavesnode;
+ if (ps.range(1,100) > 100-tree_definition.leaves2_chance)
+ leavesnode=tree_definition.leaves2node;
+ v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
+ if(vmanip.m_area.contains(p1) == false)
+ return;
+ u32 vi = vmanip.m_area.index(p1);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ return;
+ vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode;
+}
+
+void tree_fruit_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
+ TreeDef &tree_definition)
+{
+ v3s16 p1 = v3s16(myround(p0.X),myround(p0.Y),myround(p0.Z));
+ if(vmanip.m_area.contains(p1) == false)
+ return;
+ u32 vi = vmanip.m_area.index(p1);
+ if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+ && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ return;
+ vmanip.m_data[vmanip.m_area.index(p1)] = tree_definition.fruitnode;
}
irr::core::matrix4 setRotationAxisRadians(irr::core::matrix4 M, double angle, v3f axis)
return translated;
}
-#if 0
-static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
- INodeDefManager *ndef)
+void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
+ INodeDefManager *ndef, int seed)
{
- MapNode treenode(ndef->getId("mapgen_jungletree"));
- MapNode leavesnode(ndef->getId("mapgen_leaves"));
-
+ /*
+ NOTE: Tree-placing code is currently duplicated in the engine
+ and in games that have saplings; both are deprecated but not
+ replaced yet
+ */
+ content_t c_tree = ndef->getId("mapgen_jungletree");
+ content_t c_leaves = ndef->getId("mapgen_jungleleaves");
+ if (c_tree == CONTENT_IGNORE)
+ c_tree = ndef->getId("mapgen_tree");
+ if (c_leaves == CONTENT_IGNORE)
+ c_leaves = ndef->getId("mapgen_leaves");
+
+ MapNode treenode(c_tree);
+ MapNode leavesnode(c_leaves);
+
+ PseudoRandom pr(seed);
for(s16 x=-1; x<=1; x++)
for(s16 z=-1; z<=1; z++)
{
- if(myrand_range(0, 2) == 0)
+ if(pr.range(0, 2) == 0)
continue;
v3s16 p1 = p0 + v3s16(x,0,z);
v3s16 p2 = p0 + v3s16(x,-1,z);
- if(vmanip.m_area.contains(p2)
- && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
- vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
- else if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ u32 vi1 = vmanip.m_area.index(p1);
+ u32 vi2 = vmanip.m_area.index(p2);
+
+ if (vmanip.m_area.contains(p2) &&
+ vmanip.m_data[vi2].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi2] = treenode;
+ else if (vmanip.m_area.contains(p1) &&
+ vmanip.m_data[vi1].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi1] = treenode;
}
+ vmanip.m_data[vmanip.m_area.index(p0)] = treenode;
- s16 trunk_h = myrand_range(8, 12);
+ s16 trunk_h = pr.range(8, 12);
v3s16 p1 = p0;
- for(s16 ii=0; ii<trunk_h; ii++)
+ for (s16 ii=0; ii<trunk_h; ii++)
{
- if(vmanip.m_area.contains(p1))
- vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+ if (vmanip.m_area.contains(p1)) {
+ u32 vi = vmanip.m_area.index(p1);
+ if (vmanip.m_data[vi].getContent() == CONTENT_AIR)
+ vmanip.m_data[vi] = treenode;
+ }
p1.Y++;
}
s16 d = 1;
v3s16 p(
- myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
- myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
- myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+ pr.range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+ pr.range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+ pr.range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
);
for(s16 z=0; z<=d; z++)
if(vmanip.m_area.contains(p) == false)
continue;
u32 vi = vmanip.m_area.index(p);
- if(vmanip.m_data[vi].getContent() != CONTENT_AIR
- && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+ if (vmanip.m_data[vi].getContent() != CONTENT_AIR &&
+ vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
continue;
u32 i = leaves_a.index(x,y,z);
if(leaves_d[i] == 1)
vmanip.m_data[vi] = leavesnode;
}
}
-#endif
}; // namespace treegen