diff --git a/MCGalaxy/Blocks/Physics/OtherPhysics.cs b/MCGalaxy/Blocks/Physics/OtherPhysics.cs index 89771d0cb..f082ef063 100644 --- a/MCGalaxy/Blocks/Physics/OtherPhysics.cs +++ b/MCGalaxy/Blocks/Physics/OtherPhysics.cs @@ -124,7 +124,7 @@ namespace MCGalaxy.Blocks.Physics { Tree tree = Tree.Find(lvl.TreeType); if (tree == null) tree = new NormalTree(); - tree.SetData(rand, tree.DefaultValue(rand)); + tree.SetData(rand, tree.DefaultSize(rand)); tree.Generate(x, y, z, (xT, yT, zT, bT) => { if (bT == Block.leaf && lvl.GetTile(xT, yT, zT) != Block.air) return; diff --git a/MCGalaxy/Commands/building/CmdTree.cs b/MCGalaxy/Commands/building/CmdTree.cs index 873e5e533..61e9194ce 100644 --- a/MCGalaxy/Commands/building/CmdTree.cs +++ b/MCGalaxy/Commands/building/CmdTree.cs @@ -30,38 +30,52 @@ namespace MCGalaxy.Commands.Building { public override void Use(Player p, string message) { if (Player.IsSuper(p)) { MessageInGameOnly(p); return; } - string[] parts = message.SplitSpaces(2); - string brushMsg = parts.Length >= 2 ? parts[1] : ""; + string[] parts = message.SplitSpaces(3); + + DrawArgs dArgs = default(DrawArgs); + dArgs.size = -1; Tree tree = Tree.Find(parts[0]); if (tree == null) { - brushMsg = message; + dArgs.brushMsg = message; tree = new NormalTree(); } - - DrawArgs dArgs = default(DrawArgs); dArgs.tree = tree; - dArgs.brushMsg = brushMsg; - dArgs.value = -1; - - if (brushMsg != "") { - if (!p.group.CanExecute("brush")) { - Player.Message(p, "You cannot use %T/brush%S, so therefore cannot use %T/tree%S with a brush."); return; + + int size; + if (parts.Length > 1 && int.TryParse(parts[1], out size)) { + if (size < tree.MinSize) { + Player.Message(p, "Value must be {0} or above for {1} trees.", tree.MinSize, parts[0]); return; + } + if (size > tree.MaxSize) { + Player.Message(p, "Value must be {0} or below for {1} trees.", tree.MaxSize, parts[0]); return; } - Brush brush = ParseBrush(dArgs.brushMsg, p, 0, 0); - if (brush == null) return; - } - + dArgs.size = size; + dArgs.brushMsg = parts.Length >= 3 ? parts[2] : ""; // type value brush + } else { + dArgs.brushMsg = parts.Length >= 2 ? parts[1] : ""; // type brush + } + + if (!CheckBrush(p, dArgs.brushMsg)) return; Player.Message(p, "Select where you wish your tree to grow"); p.MakeSelection(1, dArgs, DoTree); } + + static bool CheckBrush(Player p, string brushMsg) { + if (brushMsg == "") return true; + + if (!p.group.CanExecute("brush")) { + Player.Message(p, "You cannot use %T/brush%S, so therefore cannot use %T/tree%S with a brush."); return false; + } + return ParseBrush(brushMsg, p, 0, 0) != null; + } bool DoTree(Player p, Vec3S32[] marks, object state, byte type, byte extType) { DrawArgs dArgs = (DrawArgs)state; TreeDrawOp op = new TreeDrawOp(); op.Tree = dArgs.tree; - op.Value = dArgs.value; + op.Size = dArgs.size; Brush brush = null; if (dArgs.brushMsg != "") brush = ParseBrush(dArgs.brushMsg, p, type, extType); @@ -83,11 +97,13 @@ namespace MCGalaxy.Commands.Building { return brush.Construct(args); } - struct DrawArgs { public Tree tree; public string brushMsg; public int value; } + struct DrawArgs { public Tree tree; public string brushMsg; public int size; } public override void Help(Player p) { Player.Message(p, "%T/tree [type] %H- Draws a tree."); + Player.Message(p, "%T/tree [type] [size] %H- Draws a tree of given size."); Player.Message(p, "%T/tree [type] [brush name] "); + Player.Message(p, "%T/tree [type] [size] [brush name] "); Player.Message(p, "%H Types: &f{0}", Tree.TreeTypes.Join(t => t.Key)); Player.Message(p, "%H For help about brushes, type %T/help brush%H."); } diff --git a/MCGalaxy/Drawing/DrawOps/TreeDrawOp.cs b/MCGalaxy/Drawing/DrawOps/TreeDrawOp.cs index 8c571115c..5323d67c7 100644 --- a/MCGalaxy/Drawing/DrawOps/TreeDrawOp.cs +++ b/MCGalaxy/Drawing/DrawOps/TreeDrawOp.cs @@ -37,9 +37,9 @@ namespace MCGalaxy.Drawing.Ops { public Tree Tree; static Brush defBrush = new SolidBrush(Block.leaf, 0); - public int Value = -1; + public int Size = -1; - public override long BlocksAffected(Level lvl, Vec3S32[] marks) { return -1; } + public override long BlocksAffected(Level lvl, Vec3S32[] marks) { return Tree.EstimateBlocksAffected(); } public override void Perform(Vec3S32[] marks, Brush brush, Action output) { if (brush == null) brush = defBrush; @@ -60,7 +60,7 @@ namespace MCGalaxy.Drawing.Ops { public override void SetMarks(Vec3S32[] marks) { base.SetMarks(marks); - int value = Value != -1 ? Value : Tree.DefaultValue(random); + int value = Size != -1 ? Size : Tree.DefaultSize(random); Tree.SetData(random, value); Max.Y += Tree.height; diff --git a/MCGalaxy/Generator/Foliage/AshTree.cs b/MCGalaxy/Generator/Foliage/AshTree.cs index 7cf4b79e0..0351fef10 100644 --- a/MCGalaxy/Generator/Foliage/AshTree.cs +++ b/MCGalaxy/Generator/Foliage/AshTree.cs @@ -23,60 +23,62 @@ using MCGalaxy.Drawing.Ops; namespace MCGalaxy.Generator.Foliage { public sealed class AshTree : Tree { - int branchBaseHeight, branchAmount; - const int maxExtent = 5, maxBranchHeight = 10, maxCluster = 3; + int branchBaseHeight, branchAmount; + const int maxExtent = 5, maxBranchHeight = 10, maxCluster = 3; List branch = new List(); - public override int DefaultValue(Random rnd) { return rnd.Next(5, 10); } + public override int EstimateBlocksAffected() { return height * height * height; } + + public override int DefaultSize(Random rnd) { return rnd.Next(5, 10); } public override void SetData(Random rnd, int value) { this.rnd = rnd; height = (byte)value; size = (byte)(maxExtent + maxCluster); - branchBaseHeight = height / 4; - branchAmount = rnd.Next(10, 25); + branchBaseHeight = height / 4; + branchAmount = rnd.Next(10, 25); } public override void Generate(ushort x, ushort y, ushort z, TreeOutput output) { - // Do base trunk + // Do base trunk Vec3S32 p1 = new Vec3S32(x, y, z); - Vec3S32 p2 = new Vec3S32(x, y + height, z); - Line(p1, p2, output); - - for (int i = 0; i < branchAmount; i++) { - DoBranch(x, y, z, output); - } + Vec3S32 p2 = new Vec3S32(x, y + height, z); + Line(p1, p2, output); + + for (int i = 0; i < branchAmount; i++) { + DoBranch(x, y, z, output); + } } - - void DoBranch(int x, int y, int z, TreeOutput output) { - int dx = rnd.Next(-maxExtent, maxExtent); - int dz = rnd.Next(-maxExtent, maxExtent); - int clusterSize = rnd.Next(1, maxCluster); - int branchStart = rnd.Next(branchBaseHeight, height); - int branchMax = branchStart + rnd.Next(3, maxBranchHeight); - - int R = clusterSize; - Vec3S32[] marks = new [] { - new Vec3S32(x + dx - R, y + branchMax - R, z + dz - R), - new Vec3S32(x + dx + R, y + branchMax + R, z + dz + R) }; - - DrawOp op = new EllipsoidDrawOp(); - Brush brush = new RandomBrush(new [] { new ExtBlock(Block.leaf, 0) }); - op.SetMarks(marks); - op.Perform(marks, brush, b => output(b.X, b.Y, b.Z, b.Block)); - - Vec3S32 p1 = new Vec3S32(x, branchStart, z); - Vec3S32 p2 = new Vec3S32(x + dx, y + branchMax, z + dz); - Line(p1, p2, output); - } + + void DoBranch(int x, int y, int z, TreeOutput output) { + int dx = rnd.Next(-maxExtent, maxExtent); + int dz = rnd.Next(-maxExtent, maxExtent); + int clusterSize = rnd.Next(1, maxCluster); + int branchStart = rnd.Next(branchBaseHeight, height); + int branchMax = branchStart + rnd.Next(3, maxBranchHeight); + + int R = clusterSize; + Vec3S32[] marks = new [] { + new Vec3S32(x + dx - R, y + branchMax - R, z + dz - R), + new Vec3S32(x + dx + R, y + branchMax + R, z + dz + R) }; + + DrawOp op = new EllipsoidDrawOp(); + Brush brush = new RandomBrush(new [] { new ExtBlock(Block.leaf, 0) }); + op.SetMarks(marks); + op.Perform(marks, brush, b => output(b.X, b.Y, b.Z, b.Block)); + + Vec3S32 p1 = new Vec3S32(x, branchStart, z); + Vec3S32 p2 = new Vec3S32(x + dx, y + branchMax, z + dz); + Line(p1, p2, output); + } void Line(Vec3S32 p1, Vec3S32 p2, TreeOutput output) { LineDrawOp.DrawLine(p1.X, p1.Y, p1.Z, 100, p2.X, p2.Y, p2.Z, branch); foreach (Vec3S32 P in branch) { - output((ushort)P.X, (ushort)P.Y, (ushort)P.Z, Block.trunk); + output((ushort)P.X, (ushort)P.Y, (ushort)P.Z, Block.trunk); } branch.Clear(); } diff --git a/MCGalaxy/Generator/Foliage/ForesterTrees.cs b/MCGalaxy/Generator/Foliage/ForesterTrees.cs index 8a1f9bca3..80b67c07a 100644 --- a/MCGalaxy/Generator/Foliage/ForesterTrees.cs +++ b/MCGalaxy/Generator/Foliage/ForesterTrees.cs @@ -39,7 +39,8 @@ namespace MCGalaxy.Generator.Foliage { protected const float EDGEHEIGHT = 25f; protected const bool ROOTBUTTRESSES = true; - public override int DefaultValue(Random rnd) { return 40; } + public override int EstimateBlocksAffected() { return height * height * height; } + public override void SetData(Random rnd, int value) { this.rnd = rnd; height = (byte)value; } /// Outputs the blocks generated by this tree at the given coordinates. @@ -332,7 +333,7 @@ namespace MCGalaxy.Generator.Foliage { /// This kind of tree is designed to resemble a deciduous tree. public class RoundTree : ProceduralTree { - public override int DefaultValue(Random rnd) { return rnd.Next(6, 11); } + public override int DefaultSize(Random rnd) { return rnd.Next(6, 11); } public override void Prepare() { base.Prepare(); @@ -366,7 +367,7 @@ namespace MCGalaxy.Generator.Foliage { /// This kind of tree is designed to resemble a conifer tree. public class ConeTree : ProceduralTree { - public override int DefaultValue(Random rnd) { return rnd.Next(15, 31); } + public override int DefaultSize(Random rnd) { return rnd.Next(15, 31); } public override void Prepare() { base.Prepare(); @@ -390,7 +391,7 @@ namespace MCGalaxy.Generator.Foliage { /// This kind of tree is designed to resemble a rainforest tree. public class RainforestTree : ProceduralTree { - public override int DefaultValue(Random rnd) { return rnd.Next(6, 11); } + public override int DefaultSize(Random rnd) { return rnd.Next(6, 11); } public override void Prepare() { base.Prepare(); @@ -421,7 +422,7 @@ namespace MCGalaxy.Generator.Foliage { /// This kind of tree is designed to resemble a mangrove tree. public class MangroveTree : RoundTree { - public override int DefaultValue(Random rnd) { return rnd.Next(10, 21); } + public override int DefaultSize(Random rnd) { return rnd.Next(10, 21); } public override void Prepare() { base.Prepare(); @@ -439,7 +440,9 @@ namespace MCGalaxy.Generator.Foliage { public sealed class BambooTree : Tree { - public override int DefaultValue(Random rnd) { return rnd.Next(4, 8); } + public override int EstimateBlocksAffected() { return height * 2; } + + public override int DefaultSize(Random rnd) { return rnd.Next(4, 8); } public override void SetData(Random rnd, int value) { height = (byte)value; @@ -463,7 +466,9 @@ namespace MCGalaxy.Generator.Foliage { public sealed class PalmTree : Tree { - public override int DefaultValue(Random rnd) { return rnd.Next(4, 8); } + public override int EstimateBlocksAffected() { return height + 8; } + + public override int DefaultSize(Random rnd) { return rnd.Next(4, 8); } public override void SetData(Random rnd, int value) { height = (byte)value; diff --git a/MCGalaxy/Generator/Foliage/OakTree.cs b/MCGalaxy/Generator/Foliage/OakTree.cs index 6bb91dd51..d3fb64887 100644 --- a/MCGalaxy/Generator/Foliage/OakTree.cs +++ b/MCGalaxy/Generator/Foliage/OakTree.cs @@ -25,7 +25,11 @@ namespace MCGalaxy.Generator.Foliage { int numBranches, maxExtent, maxBranchHeight, trunkHeight; List branch = new List(); - public override int DefaultValue(Random rnd) { return rnd.Next(0, 11); } + public override int MinSize { get { return 0; } } + + public override int EstimateBlocksAffected() { return height * height * height; } + + public override int DefaultSize(Random rnd) { return rnd.Next(0, 11); } public override void SetData(Random rnd, int value) { numBranches = value; @@ -104,7 +108,7 @@ namespace MCGalaxy.Generator.Foliage { LineDrawOp.DrawLine(p1.X, p1.Y, p1.Z, 100, p2.X, p2.Y, p2.Z, branch); foreach (Vec3S32 P in branch) { - output((ushort)P.X, (ushort)P.Y, (ushort)P.Z, Block.trunk); + output((ushort)P.X, (ushort)P.Y, (ushort)P.Z, Block.trunk); } branch.Clear(); } diff --git a/MCGalaxy/Generator/Foliage/StandardTrees.cs b/MCGalaxy/Generator/Foliage/StandardTrees.cs index 52409e98e..2a71e8d5a 100644 --- a/MCGalaxy/Generator/Foliage/StandardTrees.cs +++ b/MCGalaxy/Generator/Foliage/StandardTrees.cs @@ -28,8 +28,10 @@ using System; namespace MCGalaxy.Generator.Foliage { public sealed class CactusTree : Tree { + + public override int EstimateBlocksAffected() { return height + 3 * 2; } - public override int DefaultValue(Random rnd) { return rnd.Next(3, 6); } + public override int DefaultSize(Random rnd) { return rnd.Next(3, 6); } public override void SetData(Random rnd, int value) { height = (byte)value; @@ -57,7 +59,9 @@ namespace MCGalaxy.Generator.Foliage { public sealed class NormalTree : Tree { - public override int DefaultValue(Random rnd) { return rnd.Next(5, 8); } + public override int EstimateBlocksAffected() { return height + size * size * size; } + + public override int DefaultSize(Random rnd) { return rnd.Next(5, 8); } public override void SetData(Random rnd, int value) { height = (byte)value; @@ -86,7 +90,9 @@ namespace MCGalaxy.Generator.Foliage { public sealed class ClassicTree : Tree { - public override int DefaultValue(Random rnd) { return rnd.Next(3, 7); } + public override int EstimateBlocksAffected() { return height + 65; } + + public override int DefaultSize(Random rnd) { return rnd.Next(3, 7); } public override void SetData(Random rnd, int value) { height = (byte)value; @@ -119,7 +125,9 @@ namespace MCGalaxy.Generator.Foliage { public sealed class SwampTree : Tree { - public override int DefaultValue(Random rnd) { return rnd.Next(4, 8); } + public override int EstimateBlocksAffected() { return height + 145; } + + public override int DefaultSize(Random rnd) { return rnd.Next(4, 8); } public override void SetData(Random rnd, int value) { height = (byte)value; diff --git a/MCGalaxy/Generator/Foliage/Tree.cs b/MCGalaxy/Generator/Foliage/Tree.cs index 135c1caf9..06ea8981c 100644 --- a/MCGalaxy/Generator/Foliage/Tree.cs +++ b/MCGalaxy/Generator/Foliage/Tree.cs @@ -24,18 +24,22 @@ namespace MCGalaxy.Generator.Foliage { public delegate void TreeOutput(ushort x, ushort y, ushort z, byte block); public abstract class Tree { - protected internal byte height, size; + protected internal int height, size; protected Random rnd; - /// Calculates a random default value (usually used for height) for this tree. - public abstract int DefaultValue(Random rnd); - - /// Minimum allowed value (usually used for height) for this tree. - public virtual int MinValue { get { return 3; } } - /// Maximum allowed value (usually used for height) for this tree. - public virtual int MaxValue { get { return 100; } } + /// Minimum allowed size (usually means height) for this tree. + public virtual int MinSize { get { return 3; } } + + /// Maximum allowed size (usually means height) for this tree. + public virtual int MaxSize { get { return 100; } } + /// Estimated the maximum number of blocks affected by this tree. + public abstract int EstimateBlocksAffected(); + + /// Calculates a random default size (usually means height) for this tree. + public abstract int DefaultSize(Random rnd); + /// Initalises data (e.g. height and size) for this tree using the input value. public abstract void SetData(Random rnd, int value); diff --git a/MCGalaxy/Generator/RealisticMapGen.cs b/MCGalaxy/Generator/RealisticMapGen.cs index 455318b6a..2282c636a 100644 --- a/MCGalaxy/Generator/RealisticMapGen.cs +++ b/MCGalaxy/Generator/RealisticMapGen.cs @@ -140,7 +140,7 @@ namespace MCGalaxy.Generator { if (genParams.UseCactus) tree = new CactusTree(); else tree = new NormalTree(); - tree.SetData(rand, tree.DefaultValue(rand)); + tree.SetData(rand, tree.DefaultSize(rand)); tree.Generate(x, (ushort)(y + 1), z, (xT, yT, zT, bT) => { if (Lvl.GetTile(xT, yT, zT) == Block.air)