aboutsummaryrefslogtreecommitdiff
path: root/advtrains
Commit message (Collapse)AuthorAge
* Fix bug introduced by last commit (revert change)orwell962017-04-12
|
* Add privilege for basic train operation.orwell962017-04-09
| | | | This privilege is granted to singleplayer by default, but is not granted on servers. This prevents unexperienced or evil players from breaking automatic train operation on servers.
* record_protection_violation: fix player name not being passedorwell962017-04-07
|
* Fix #59orwell962017-04-05
|
* Actually check for protection when placing trains and use the train_place ↵orwell962017-04-02
| | | | privilege
* Assert some variable types obtained from lua automationorwell962017-03-30
|
* Add support to display text to passengers and on the outside of the trainorwell962017-03-30
| | | | | Outside is currently displayed as infotext. TODO: signs-like draw it on the wagon FIXME: When object properties are set, for some reason the animation restarts
* Respect protection_bypass privilege, fix crash with areas and properly ↵orwell962017-03-30
| | | | record protection violations
* Fix privilege enforcement being uselessorwell962017-03-16
| | | | Privilege violations caused an error message but didn't abort the operation
* Fix Atc arrows pointing into wrong directionorwell962017-03-12
|
* Screw buttonlike rules for wall signals and use regular rules.orwell962017-03-12
|
* Redo rail modelsorwell962017-03-12
| | | | Use multiple textures for slope objects, include mbb's rail textures and make curves and switches look better. Also add cable template.
* Don't drop items in creative mode when player gets overrun by trainorwell962017-03-11
|
* "Sneak" instead of "Shift" for the sneak keyorwell962017-03-09
|
* Update manual and include everything in repoorwell962017-03-09
|
* Improve debug outputs of couples and increase maximum distanceorwell962017-03-03
|
* Only get on by walking in when there's a platform, improve get off handlingorwell962017-02-28
|
* Add passive component namingorwell962017-02-28
|
* Add ceiling-mounted signalorwell962017-02-28
| | | | This is the wall signal as ceiling variant. Because the trackdb can only save 4 rotation values, we need a ceiling version of this.
* Fix collision issuesorwell962017-02-21
|
* Also check positions on high platforms at entering doorsorwell962017-02-21
|
* Only place rails on solid nodesorwell962017-02-21
|
* Fix manual operation of mesecon switchesorwell962017-02-20
|
* Fix crash when ATC rail exists but no command is saved.orwell962017-02-20
| | | | | Crash was caused by a concatenation for a debug message. atprint can handle nil if passed as separate parameter Setting the train's atc command to nil just means that there is no command.
* don't pass unexistant variable to train_step_b (fixes #46)orwell962017-02-17
|
* use mesecons_switch as correct dependency for luaautomationorwell962017-02-15
|
* fix crash on seatpc nilorwell962017-02-15
|
* fix #34 - end_index not set when step_a returned in phase 2orwell962017-02-15
|
* Proper implementation for getting on by walking into train, rework damage ↵orwell962017-02-09
| | | | and player controls in train, fix death and join bugs, do not spawn bones on death
* Merge PR from gpcf (Get on by walking in)orwell962017-02-07
|\
| * Merge branch 'master' of https://github.com/orwell96/advtrainsGabriel Pérez-Cerezo2017-02-05
| |\
| * | Found out why collision box does not fit trainGabriel Pérez-Cerezo2017-01-29
| | |
| * | Added getting on and off by walking in and out. Default seat on subway is ↵Gabriel Pérez-Cerezo2017-01-29
| | | | | | | | | | | | now passenger seat.
* | | Use identical proxy environment with swapped metatable to not having to ↵orwell962017-02-07
| | | | | | | | | | | | setfenv every function in F.
* | | Check if node is actually loaded before querying get_meta()orwell962017-02-05
| | | | | | | | | | | | Known to cause a segfault in engine sometimes.
* | | Do not invalidate paths unnecessarilyorwell962017-02-05
| | | | | | | | | | | | Recomputing paths needs time and computing power, so do this only when really necessary
* | | Fix "lock couples" checkbox on wagon properties formorwell962017-02-05
| | |
* | | Fix ATC components being randomly ignored by trains.orwell962017-02-05
| | | | | | | | | | | | | | | Also add warnings to off_track stuff Also pack for release
* | | Fix itrainmaporwell962017-02-05
| | |
* | | Fix LuaAtc Interrupt savingorwell962017-02-05
| | | | | | | | | | | | The timer was loaded, but not saved, leading to it being counted from 0 upwards every restart, which of course broke interrupts.
* | | Even more bugfixesorwell962017-02-04
| |/ |/| | | | | | | | | | | - add translations of all index values to invert_train - fix on_leave_node callbacks not being called when train reverses - fix callbacks on train creation and destruction - Fix warning when saving ATC rail info
* | Commit 1.6.2orwell962017-02-04
| | | | | | | | | | | | | | | | - Add some more stuff to API for LuaATC rails - Warn on strange events even if debug info is disabled - save atlatc on shutdown too - fix detector rails in unloaded chunks - do not fail silently in simple ATC rails
* | fix up stuff in itrainmaporwell962017-02-03
| |
* | Revert change to node pos hashes, and rewrite trackdb to use individual ↵orwell962017-02-03
| | | | | | | | | | | | | | | | coordinates The precision of integers was not sufficient for saving pos node hashes in most cases, leading to strange bugs. This fixes broken ATC rails, broken LuaAutomation stuff and trackdb on Windows. Probably also fixes trains randomly stopping.
* | Add quick position lookup by punching nodesorwell962017-02-03
| |
* | add wallmounted light signalorwell962017-02-03
| |
* | Fix itrainmap not workingorwell962017-02-03
| |
* | Merge PR from mbb: add better textures and craftsorwell962017-02-02
|\ \
| * | add better textures and craftsmbblp2017-02-02
| | |
* | | Add documentation and pack for releaseorwell962017-02-02
| | |
ass="hl ppc">#include "nodedef.h" #include "treegen.h" #include "voxelalgorithms.h" namespace treegen { void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree, const NodeDefManager *ndef, s32 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")); if (treenode == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_tree' is invalid!" << std::endl; if (leavesnode == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_leaves' is invalid!" << std::endl; if (applenode == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_apple' is invalid!" << std::endl; PseudoRandom pr(seed); s16 trunk_h = pr.range(4, 5); v3s16 p1 = p0; for (s16 ii = 0; ii < trunk_h; ii++) { if (vmanip.m_area.contains(p1)) { u32 vi = vmanip.m_area.index(p1); vmanip.m_data[vi] = treenode; } p1.Y++; } // p1 is now the last piece of the trunk p1.Y -= 1; VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2)); Buffer<u8> leaves_d(leaves_a.getVolume()); for (s32 i = 0; i < leaves_a.getVolume(); i++) leaves_d[i] = 0; // Force leaves at near the end of the trunk s16 d = 1; for (s16 z = -d; z <= d; z++) for (s16 y = -d; y <= d; y++) for (s16 x = -d; x <= d; x++) { leaves_d[leaves_a.index(v3s16(x, y, z))] = 1; } // Add leaves randomly for (u32 iii = 0; iii < 7; iii++) { v3s16 p( 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++) for (s16 y = 0; y <= d; y++) for (s16 x = 0; x <= d; x++) { leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1; } } // Blit leaves to vmanip for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++) for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) { v3s16 pmin(leaves_a.MinEdge.X, y, z); u32 i = leaves_a.index(pmin); u32 vi = vmanip.m_area.index(pmin + p1); for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) { v3s16 p(x, y, z); if (vmanip.m_area.contains(p + p1) && (vmanip.m_data[vi].getContent() == CONTENT_AIR || vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) { if (leaves_d[i] == 1) { bool is_apple = pr.range(0, 99) < 10; if (is_apple_tree && is_apple) vmanip.m_data[vi] = applenode; else vmanip.m_data[vi] = leavesnode; } } vi++; i++; } } } // L-System tree LUA spawner treegen::error spawn_ltree(ServerMap *map, v3s16 p0, const NodeDefManager *ndef, const TreeDef &tree_definition) { std::map<v3s16, MapBlock*> modified_blocks; MMVManip vmanip(map); v3s16 tree_blockp = getNodeBlockPos(p0); treegen::error e; vmanip.initialEmerge(tree_blockp - v3s16(1, 1, 1), tree_blockp + v3s16(1, 3, 1)); e = make_ltree(vmanip, p0, ndef, tree_definition); if (e != SUCCESS) return e; voxalgo::blit_back_with_light(map, &vmanip, &modified_blocks); // Send a MEET_OTHER event MapEditEvent event; event.type = MEET_OTHER; for (auto &modified_block : modified_blocks) event.modified_blocks.insert(modified_block.first); map->dispatchEvent(event); return SUCCESS; } //L-System tree generator treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, TreeDef tree_definition) { s32 seed; if (tree_definition.explicit_seed) seed = tree_definition.seed + 14002; else seed = p0.X * 2 + p0.Y * 4 + p0.Z; // use the tree position to seed PRNG PseudoRandom ps(seed); // chance of inserting abcd rules double prop_a = 9; double prop_b = 8; double prop_c = 7; double prop_d = 6; //randomize tree growth level, minimum=2 s16 iterations = tree_definition.iterations; if (tree_definition.iterations_random_level > 0) 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)(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; position.X = p0.X; position.Y = p0.Y; position.Z = p0.Z; std::stack <core::matrix4> stack_orientation; std::stack <v3f> stack_position; //generate axiom std::string axiom = tree_definition.initial_axiom; for (s16 i = 0; i < iterations; i++) { std::string temp; for (s16 j = 0; j < (s16)axiom.size(); j++) { char axiom_char = axiom.at(j); switch (axiom_char) { case 'A': temp += tree_definition.rules_a; break; case 'B': temp += tree_definition.rules_b; break; case 'C': temp += tree_definition.rules_c; break; case 'D': temp += tree_definition.rules_d; break; case 'a': if (prop_a >= ps.range(1, 10)) temp += tree_definition.rules_a; break; case 'b': if (prop_b >= ps.range(1, 10)) temp += tree_definition.rules_b; break; case 'c': if (prop_c >= ps.range(1, 10)) temp += tree_definition.rules_c; break; case 'd': if (prop_d >= ps.range(1, 10)) temp += tree_definition.rules_d; break; default: temp += axiom_char; break; } } axiom = temp; } // Add trunk nodes below a wide trunk to avoid gaps when tree is on sloping ground if (tree_definition.trunk_type == "double") { tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z), tree_definition ); tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z + 1), tree_definition ); tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z + 1), tree_definition ); } else if (tree_definition.trunk_type == "crossed") { tree_trunk_placement( vmanip, v3f(position.X + 1, position.Y - 1, position.Z), tree_definition ); tree_trunk_placement( vmanip, v3f(position.X - 1, position.Y - 1, position.Z), tree_definition ); tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z + 1), tree_definition ); tree_trunk_placement( vmanip, v3f(position.X, position.Y - 1, position.Z - 1), tree_definition ); } /* build tree out of generated axiom Key for Special L-System Symbols used in Axioms 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 D - replace with rules set D a - replace with rules set A, chance 90% b - replace with rules set B, chance 80% c - replace with rules set C, chance 70% d - replace with rules set D, chance 60% + - yaw the turtle right by angle degrees - - yaw the turtle left by angle degrees & - pitch the turtle down by angle degrees ^ - pitch the turtle up by angle degrees / - roll the turtle to the right by angle degrees * - roll the turtle to the left by angle degrees [ - save in stack current state info ] - recover from stack state info */ s16 x,y,z; for (s16 i = 0; i < (s16)axiom.size(); i++) { char axiom_char = axiom.at(i); core::matrix4 temp_rotation; temp_rotation.makeIdentity(); v3f dir; switch (axiom_char) { case 'G': 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 ); } else 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': 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)) { 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 ); } else 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()) { s16 size = 1; 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) { 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; 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); break; case ']': if (stack_orientation.empty()) return UNBALANCED_BRACKETS; rotation = stack_orientation.top(); stack_orientation.pop(); position = stack_position.top(); stack_position.pop(); break; case '+': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians + angleOffset_in_radians, v3f(0, 0, 1)); rotation *= temp_rotation; break; case '-': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians + angleOffset_in_radians, v3f(0, 0, -1)); rotation *= temp_rotation; break; case '&': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians + angleOffset_in_radians, v3f(0, 1, 0)); rotation *= temp_rotation; break; case '^': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians + angleOffset_in_radians, v3f(0, -1, 0)); rotation *= temp_rotation; break; case '*': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians, v3f(1, 0, 0)); rotation *= temp_rotation; break; case '/': temp_rotation.makeIdentity(); temp_rotation = setRotationAxisRadians(temp_rotation, angle_in_radians, v3f(-1, 0, 0)); rotation *= temp_rotation; break; default: break; } } return SUCCESS; } void tree_node_placement(MMVManip &vmanip, v3f p0, MapNode node) { v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); if (!vmanip.m_area.contains(p1)) 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)] = node; } void tree_trunk_placement(MMVManip &vmanip, v3f p0, TreeDef &tree_definition) { v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); if (!vmanip.m_area.contains(p1)) return; u32 vi = vmanip.m_area.index(p1); content_t current_node = vmanip.m_data[vi].getContent(); if (current_node != CONTENT_AIR && current_node != CONTENT_IGNORE && current_node != tree_definition.leavesnode.getContent() && current_node != tree_definition.leaves2node.getContent() && current_node != tree_definition.fruitnode.getContent()) return; vmanip.m_data[vi] = tree_definition.trunknode; } void tree_leaves_placement(MMVManip &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)) 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_chance > 0) { 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)] = leavesnode; } else if (ps.range(1, 100) > 20) { vmanip.m_data[vmanip.m_area.index(p1)] = leavesnode; } } void tree_single_leaves_placement(MMVManip &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)) 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(MMVManip &vmanip, v3f p0, TreeDef &tree_definition) { v3s16 p1 = v3s16(myround(p0.X), myround(p0.Y), myround(p0.Z)); if (!vmanip.m_area.contains(p1)) 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) { double c = cos(angle); double s = sin(angle); double t = 1.0 - c; double tx = t * axis.X; double ty = t * axis.Y; double tz = t * axis.Z; double sx = s * axis.X; double sy = s * axis.Y; double sz = s * axis.Z; M[0] = tx * axis.X + c; M[1] = tx * axis.Y + sz; M[2] = tx * axis.Z - sy; M[4] = ty * axis.X - sz; M[5] = ty * axis.Y + c; M[6] = ty * axis.Z + sx; M[8] = tz * axis.X + sy; M[9] = tz * axis.Y - sx; M[10] = tz * axis.Z + c; return M; } v3f transposeMatrix(irr::core::matrix4 M, v3f v) { v3f translated; double x = M[0] * v.X + M[4] * v.Y + M[8] * v.Z +M[12]; double y = M[1] * v.X + M[5] * v.Y + M[9] * v.Z +M[13]; double z = M[2] * v.X + M[6] * v.Y + M[10] * v.Z +M[14]; translated.X = x; translated.Y = y; translated.Z = z; return translated; } void make_jungletree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, s32 seed) { /* 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"); if (c_tree == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_jungletree' is invalid!" << std::endl; if (c_leaves == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_jungleleaves' is invalid!" << std::endl; 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 (pr.range(0, 2) == 0) continue; v3s16 p1 = p0 + v3s16(x, 0, z); v3s16 p2 = p0 + v3s16(x, -1, z); 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 = pr.range(8, 12); v3s16 p1 = p0; for (s16 ii = 0; ii < trunk_h; ii++) { if (vmanip.m_area.contains(p1)) { u32 vi = vmanip.m_area.index(p1); vmanip.m_data[vi] = treenode; } p1.Y++; } // p1 is now the last piece of the trunk p1.Y -= 1; VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3)); //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]); Buffer<u8> leaves_d(leaves_a.getVolume()); for (s32 i = 0; i < leaves_a.getVolume(); i++) leaves_d[i] = 0; // Force leaves at near the end of the trunk s16 d = 1; for (s16 z = -d; z <= d; z++) for (s16 y = -d; y <= d; y++) for (s16 x = -d; x <= d; x++) { leaves_d[leaves_a.index(v3s16(x,y,z))] = 1; } // Add leaves randomly for (u32 iii = 0; iii < 30; iii++) { v3s16 p( 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++) for (s16 y = 0; y <= d; y++) for (s16 x = 0; x <= d; x++) { leaves_d[leaves_a.index(p + v3s16(x, y, z))] = 1; } } // Blit leaves to vmanip for (s16 z = leaves_a.MinEdge.Z; z <= leaves_a.MaxEdge.Z; z++) for (s16 y = leaves_a.MinEdge.Y; y <= leaves_a.MaxEdge.Y; y++) { v3s16 pmin(leaves_a.MinEdge.X, y, z); u32 i = leaves_a.index(pmin); u32 vi = vmanip.m_area.index(pmin + p1); for (s16 x = leaves_a.MinEdge.X; x <= leaves_a.MaxEdge.X; x++) { v3s16 p(x, y, z); if (vmanip.m_area.contains(p + p1) && (vmanip.m_data[vi].getContent() == CONTENT_AIR || vmanip.m_data[vi].getContent() == CONTENT_IGNORE)) { if (leaves_d[i] == 1) vmanip.m_data[vi] = leavesnode; } vi++; i++; } } } void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, s32 seed) { /* 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_pine_tree"); content_t c_leaves = ndef->getId("mapgen_pine_needles"); content_t c_snow = ndef->getId("mapgen_snow"); if (c_tree == CONTENT_IGNORE) c_tree = ndef->getId("mapgen_tree"); if (c_leaves == CONTENT_IGNORE) c_leaves = ndef->getId("mapgen_leaves"); if (c_snow == CONTENT_IGNORE) c_snow = CONTENT_AIR; if (c_tree == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_pine_tree' is invalid!" << std::endl; if (c_leaves == CONTENT_IGNORE) errorstream << "Treegen: Mapgen alias 'mapgen_pine_needles' is invalid!" << std::endl; MapNode treenode(c_tree); MapNode leavesnode(c_leaves); MapNode snownode(c_snow); PseudoRandom pr(seed); u16 trunk_h = pr.range(9, 13); v3s16 p1 = p0; for (u16 ii = 0; ii < trunk_h; ii++) { if (vmanip.m_area.contains(p1)) { u32 vi = vmanip.m_area.index(p1); vmanip.m_data[vi] = treenode; } p1.Y++; } // Make p1 the top node of the trunk p1.Y -= 1; VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3)); Buffer<u8> leaves_d(leaves_a.getVolume()); for (s32 i = 0; i < leaves_a.getVolume(); i++) leaves_d[i] = 0; // Upper branches u16 dev = 3; for (s16 yy = -1; yy <= 1; yy++) { for (s16 zz = -dev; zz <= dev; zz++) { u32 i = leaves_a.index(v3s16(-dev, yy, zz)); u32 ia = leaves_a.index(v3s16(-dev, yy+1, zz)); for (s16 xx = -dev; xx <= dev; xx++) { if (pr.range(0, 20) <= 19 - dev) { leaves_d[i] = 1; leaves_d[ia] = 2; } i++; ia++; } } dev--; } // Centre top nodes leaves_d[leaves_a.index(v3s16(0, 1, 0))] = 1; leaves_d[leaves_a.index(v3s16(0, 2, 0))] = 1; leaves_d[leaves_a.index(v3s16(0, 3, 0))] = 2; // Lower branches s16 my = -6; for (u32 iii = 0; iii < 20; iii++) { s16 xi = pr.range(-3, 2); s16 yy = pr.range(-6, -5);