Allow providing sizes to trees.

This commit is contained in:
UnknownShadow200 2017-02-04 19:09:03 +11:00
parent a40c342079
commit 770a284212
9 changed files with 117 additions and 78 deletions

View File

@ -124,7 +124,7 @@ namespace MCGalaxy.Blocks.Physics {
Tree tree = Tree.Find(lvl.TreeType); Tree tree = Tree.Find(lvl.TreeType);
if (tree == null) tree = new NormalTree(); 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) => tree.Generate(x, y, z, (xT, yT, zT, bT) =>
{ {
if (bT == Block.leaf && lvl.GetTile(xT, yT, zT) != Block.air) return; if (bT == Block.leaf && lvl.GetTile(xT, yT, zT) != Block.air) return;

View File

@ -30,38 +30,52 @@ namespace MCGalaxy.Commands.Building {
public override void Use(Player p, string message) { public override void Use(Player p, string message) {
if (Player.IsSuper(p)) { MessageInGameOnly(p); return; } if (Player.IsSuper(p)) { MessageInGameOnly(p); return; }
string[] parts = message.SplitSpaces(2); string[] parts = message.SplitSpaces(3);
string brushMsg = parts.Length >= 2 ? parts[1] : "";
DrawArgs dArgs = default(DrawArgs);
dArgs.size = -1;
Tree tree = Tree.Find(parts[0]); Tree tree = Tree.Find(parts[0]);
if (tree == null) { if (tree == null) {
brushMsg = message; dArgs.brushMsg = message;
tree = new NormalTree(); tree = new NormalTree();
} }
DrawArgs dArgs = default(DrawArgs);
dArgs.tree = tree; dArgs.tree = tree;
dArgs.brushMsg = brushMsg;
dArgs.value = -1; int size;
if (parts.Length > 1 && int.TryParse(parts[1], out size)) {
if (brushMsg != "") { if (size < tree.MinSize) {
if (!p.group.CanExecute("brush")) { Player.Message(p, "Value must be {0} or above for {1} trees.", tree.MinSize, parts[0]); return;
Player.Message(p, "You cannot use %T/brush%S, so therefore cannot use %T/tree%S with a brush."); 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); dArgs.size = size;
if (brush == null) return; 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"); Player.Message(p, "Select where you wish your tree to grow");
p.MakeSelection(1, dArgs, DoTree); 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) { bool DoTree(Player p, Vec3S32[] marks, object state, byte type, byte extType) {
DrawArgs dArgs = (DrawArgs)state; DrawArgs dArgs = (DrawArgs)state;
TreeDrawOp op = new TreeDrawOp(); TreeDrawOp op = new TreeDrawOp();
op.Tree = dArgs.tree; op.Tree = dArgs.tree;
op.Value = dArgs.value; op.Size = dArgs.size;
Brush brush = null; Brush brush = null;
if (dArgs.brushMsg != "") brush = ParseBrush(dArgs.brushMsg, p, type, extType); if (dArgs.brushMsg != "") brush = ParseBrush(dArgs.brushMsg, p, type, extType);
@ -83,11 +97,13 @@ namespace MCGalaxy.Commands.Building {
return brush.Construct(args); 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) { public override void Help(Player p) {
Player.Message(p, "%T/tree [type] %H- Draws a tree."); 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] <brush args>"); Player.Message(p, "%T/tree [type] [brush name] <brush args>");
Player.Message(p, "%T/tree [type] [size] [brush name] <brush args>");
Player.Message(p, "%H Types: &f{0}", Tree.TreeTypes.Join(t => t.Key)); 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."); Player.Message(p, "%H For help about brushes, type %T/help brush%H.");
} }

View File

@ -37,9 +37,9 @@ namespace MCGalaxy.Drawing.Ops {
public Tree Tree; public Tree Tree;
static Brush defBrush = new SolidBrush(Block.leaf, 0); 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<DrawOpBlock> output) { public override void Perform(Vec3S32[] marks, Brush brush, Action<DrawOpBlock> output) {
if (brush == null) brush = defBrush; if (brush == null) brush = defBrush;
@ -60,7 +60,7 @@ namespace MCGalaxy.Drawing.Ops {
public override void SetMarks(Vec3S32[] marks) { public override void SetMarks(Vec3S32[] marks) {
base.SetMarks(marks); base.SetMarks(marks);
int value = Value != -1 ? Value : Tree.DefaultValue(random); int value = Size != -1 ? Size : Tree.DefaultSize(random);
Tree.SetData(random, value); Tree.SetData(random, value);
Max.Y += Tree.height; Max.Y += Tree.height;

View File

@ -23,60 +23,62 @@ using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Generator.Foliage { namespace MCGalaxy.Generator.Foliage {
public sealed class AshTree : Tree { public sealed class AshTree : Tree {
int branchBaseHeight, branchAmount; int branchBaseHeight, branchAmount;
const int maxExtent = 5, maxBranchHeight = 10, maxCluster = 3; const int maxExtent = 5, maxBranchHeight = 10, maxCluster = 3;
List<Vec3S32> branch = new List<Vec3S32>(); List<Vec3S32> branch = new List<Vec3S32>();
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) { public override void SetData(Random rnd, int value) {
this.rnd = rnd; this.rnd = rnd;
height = (byte)value; height = (byte)value;
size = (byte)(maxExtent + maxCluster); size = (byte)(maxExtent + maxCluster);
branchBaseHeight = height / 4; branchBaseHeight = height / 4;
branchAmount = rnd.Next(10, 25); branchAmount = rnd.Next(10, 25);
} }
public override void Generate(ushort x, ushort y, ushort z, TreeOutput output) { 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 p1 = new Vec3S32(x, y, z);
Vec3S32 p2 = new Vec3S32(x, y + height, z); Vec3S32 p2 = new Vec3S32(x, y + height, z);
Line(p1, p2, output); Line(p1, p2, output);
for (int i = 0; i < branchAmount; i++) { for (int i = 0; i < branchAmount; i++) {
DoBranch(x, y, z, output); DoBranch(x, y, z, output);
} }
} }
void DoBranch(int x, int y, int z, TreeOutput output) { void DoBranch(int x, int y, int z, TreeOutput output) {
int dx = rnd.Next(-maxExtent, maxExtent); int dx = rnd.Next(-maxExtent, maxExtent);
int dz = rnd.Next(-maxExtent, maxExtent); int dz = rnd.Next(-maxExtent, maxExtent);
int clusterSize = rnd.Next(1, maxCluster); int clusterSize = rnd.Next(1, maxCluster);
int branchStart = rnd.Next(branchBaseHeight, height); int branchStart = rnd.Next(branchBaseHeight, height);
int branchMax = branchStart + rnd.Next(3, maxBranchHeight); int branchMax = branchStart + rnd.Next(3, maxBranchHeight);
int R = clusterSize; int R = clusterSize;
Vec3S32[] marks = new [] { 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),
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(); DrawOp op = new EllipsoidDrawOp();
Brush brush = new RandomBrush(new [] { new ExtBlock(Block.leaf, 0) }); Brush brush = new RandomBrush(new [] { new ExtBlock(Block.leaf, 0) });
op.SetMarks(marks); op.SetMarks(marks);
op.Perform(marks, brush, b => output(b.X, b.Y, b.Z, b.Block)); op.Perform(marks, brush, b => output(b.X, b.Y, b.Z, b.Block));
Vec3S32 p1 = new Vec3S32(x, branchStart, z); Vec3S32 p1 = new Vec3S32(x, branchStart, z);
Vec3S32 p2 = new Vec3S32(x + dx, y + branchMax, z + dz); Vec3S32 p2 = new Vec3S32(x + dx, y + branchMax, z + dz);
Line(p1, p2, output); Line(p1, p2, output);
} }
void Line(Vec3S32 p1, Vec3S32 p2, TreeOutput 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); LineDrawOp.DrawLine(p1.X, p1.Y, p1.Z, 100, p2.X, p2.Y, p2.Z, branch);
foreach (Vec3S32 P in 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(); branch.Clear();
} }

View File

@ -39,7 +39,8 @@ namespace MCGalaxy.Generator.Foliage {
protected const float EDGEHEIGHT = 25f; protected const float EDGEHEIGHT = 25f;
protected const bool ROOTBUTTRESSES = true; 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; } public override void SetData(Random rnd, int value) { this.rnd = rnd; height = (byte)value; }
/// <summary> Outputs the blocks generated by this tree at the given coordinates. </summary> /// <summary> Outputs the blocks generated by this tree at the given coordinates. </summary>
@ -332,7 +333,7 @@ namespace MCGalaxy.Generator.Foliage {
/// <summary> This kind of tree is designed to resemble a deciduous tree. </summary> /// <summary> This kind of tree is designed to resemble a deciduous tree. </summary>
public class RoundTree : ProceduralTree { 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() { public override void Prepare() {
base.Prepare(); base.Prepare();
@ -366,7 +367,7 @@ namespace MCGalaxy.Generator.Foliage {
/// <summary> This kind of tree is designed to resemble a conifer tree. </summary> /// <summary> This kind of tree is designed to resemble a conifer tree. </summary>
public class ConeTree : ProceduralTree { 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() { public override void Prepare() {
base.Prepare(); base.Prepare();
@ -390,7 +391,7 @@ namespace MCGalaxy.Generator.Foliage {
/// <summary> This kind of tree is designed to resemble a rainforest tree. </summary> /// <summary> This kind of tree is designed to resemble a rainforest tree. </summary>
public class RainforestTree : ProceduralTree { 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() { public override void Prepare() {
base.Prepare(); base.Prepare();
@ -421,7 +422,7 @@ namespace MCGalaxy.Generator.Foliage {
/// <summary> This kind of tree is designed to resemble a mangrove tree. </summary> /// <summary> This kind of tree is designed to resemble a mangrove tree. </summary>
public class MangroveTree : RoundTree { 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() { public override void Prepare() {
base.Prepare(); base.Prepare();
@ -439,7 +440,9 @@ namespace MCGalaxy.Generator.Foliage {
public sealed class BambooTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;
@ -463,7 +466,9 @@ namespace MCGalaxy.Generator.Foliage {
public sealed class PalmTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;

View File

@ -25,7 +25,11 @@ namespace MCGalaxy.Generator.Foliage {
int numBranches, maxExtent, maxBranchHeight, trunkHeight; int numBranches, maxExtent, maxBranchHeight, trunkHeight;
List<Vec3S32> branch = new List<Vec3S32>(); List<Vec3S32> branch = new List<Vec3S32>();
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) { public override void SetData(Random rnd, int value) {
numBranches = 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); LineDrawOp.DrawLine(p1.X, p1.Y, p1.Z, 100, p2.X, p2.Y, p2.Z, branch);
foreach (Vec3S32 P in 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(); branch.Clear();
} }

View File

@ -28,8 +28,10 @@ using System;
namespace MCGalaxy.Generator.Foliage { namespace MCGalaxy.Generator.Foliage {
public sealed class CactusTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;
@ -57,7 +59,9 @@ namespace MCGalaxy.Generator.Foliage {
public sealed class NormalTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;
@ -86,7 +90,9 @@ namespace MCGalaxy.Generator.Foliage {
public sealed class ClassicTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;
@ -119,7 +125,9 @@ namespace MCGalaxy.Generator.Foliage {
public sealed class SwampTree : Tree { 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) { public override void SetData(Random rnd, int value) {
height = (byte)value; height = (byte)value;

View File

@ -24,18 +24,22 @@ namespace MCGalaxy.Generator.Foliage {
public delegate void TreeOutput(ushort x, ushort y, ushort z, byte block); public delegate void TreeOutput(ushort x, ushort y, ushort z, byte block);
public abstract class Tree { public abstract class Tree {
protected internal byte height, size; protected internal int height, size;
protected Random rnd; protected Random rnd;
/// <summary> Calculates a random default value (usually used for height) for this tree. </summary>
public abstract int DefaultValue(Random rnd);
/// <summary> Minimum allowed value (usually used for height) for this tree. </summary>
public virtual int MinValue { get { return 3; } }
/// <summary> Maximum allowed value (usually used for height) for this tree. </summary> /// <summary> Minimum allowed size (usually means height) for this tree. </summary>
public virtual int MaxValue { get { return 100; } } public virtual int MinSize { get { return 3; } }
/// <summary> Maximum allowed size (usually means height) for this tree. </summary>
public virtual int MaxSize { get { return 100; } }
/// <summary> Estimated the maximum number of blocks affected by this tree. </summary>
public abstract int EstimateBlocksAffected();
/// <summary> Calculates a random default size (usually means height) for this tree. </summary>
public abstract int DefaultSize(Random rnd);
/// <summary> Initalises data (e.g. height and size) for this tree using the input value. </summary> /// <summary> Initalises data (e.g. height and size) for this tree using the input value. </summary>
public abstract void SetData(Random rnd, int value); public abstract void SetData(Random rnd, int value);

View File

@ -140,7 +140,7 @@ namespace MCGalaxy.Generator {
if (genParams.UseCactus) tree = new CactusTree(); if (genParams.UseCactus) tree = new CactusTree();
else tree = new NormalTree(); 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) => tree.Generate(x, (ushort)(y + 1), z, (xT, yT, zT, bT) =>
{ {
if (Lvl.GetTile(xT, yT, zT) == Block.air) if (Lvl.GetTile(xT, yT, zT) == Block.air)