diff --git a/Commands/building/CmdMaze.cs b/Commands/building/CmdMaze.cs index ebe9fae73..181d2926f 100644 --- a/Commands/building/CmdMaze.cs +++ b/Commands/building/CmdMaze.cs @@ -33,27 +33,32 @@ namespace MCGalaxy.Commands public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } } public override void Use(Player p, string message) { - if (message.Length > 0 && !int.TryParse(message, out MazeDrawOp.randomizer)) { + CatchPos cpos = default(CatchPos); + if (message.Length > 0 && !int.TryParse(message, out cpos.randomizer)) { Help(p); return; } - Player.SendMessage(p, "Place two blocks to determine the edges."); + Player.SendMessage(p, "Place two blocks to determine the edges."); p.ClearBlockchange(); + p.blockchangeObject = cpos; p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1); } void Blockchange1(Player p, ushort x, ushort y, ushort z, byte type, byte extType) { RevertAndClearState(p, x, y, z); - p.blockchangeObject = new Vector3U16(x, y, z); + CatchPos cpos = (CatchPos)p.blockchangeObject; + cpos.x = x; cpos.y = y; cpos.z = z; + p.blockchangeObject = cpos; p.Blockchange += new Player.BlockchangeEventHandler(Blockchange2); } void Blockchange2(Player p, ushort x, ushort y, ushort z, byte type, byte extType) { RevertAndClearState(p, x, y, z); - Vector3U16 cpos = (Vector3U16)p.blockchangeObject; - DrawOp drawOp = new MazeDrawOp(); + CatchPos cpos = (CatchPos)p.blockchangeObject; + MazeDrawOp drawOp = new MazeDrawOp(); + drawOp.randomizer = cpos.randomizer; - if (!DrawOp.DoDrawOp(drawOp, null, p, cpos.X, cpos.Y, cpos.Z, x, y, z)) + if (!DrawOp.DoDrawOp(drawOp, null, p, cpos.x, cpos.y, cpos.z, x, y, z)) return; if (p.staticCommands) p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1); @@ -63,5 +68,7 @@ namespace MCGalaxy.Commands Player.SendMessage(p, "%T/maze"); Player.SendMessage(p, "%HGenerates a random maze between two points."); } + + struct CatchPos { public ushort x, y, z; public int randomizer; } } } diff --git a/Drawing/DrawOps/MazeDrawOp.cs b/Drawing/DrawOps/MazeDrawOp.cs index e0616bec1..b40f2cc76 100644 --- a/Drawing/DrawOps/MazeDrawOp.cs +++ b/Drawing/DrawOps/MazeDrawOp.cs @@ -21,177 +21,149 @@ using System.Security.Cryptography; using MCGalaxy.Drawing.Brushes; namespace MCGalaxy.Drawing.Ops { - - public class MazeDrawOp : CuboidHollowsDrawOp { - - public override string Name { get { return "Maze"; } } - - public static int randomizer = 0; - public static bool[,] wall; - - public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) { - int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2; - int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2; - return lenX * lenZ * 3; - } - - public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) { - int width = Max.X - Min.X; - if (width % 2 != 0) { width++; Min.X--; } - width -= 2; - int length = Max.Z - Min.Z; - if (length % 2 != 0) { length++; Min.Z--; } - length -= 2; - - if (width < 0 || length < 0) { - Player.SendMessage(p, "The corners of the maze need to be further apart."); return; - } - Player.SendMessage(p, "Generating maze... this could take a while"); - //substract 2 cause we will just make the inner. the outer wall is made seperately - wall = new bool[width+1, length+1];//+1 cause we begin at 0 so we need one object more - for (int w = 0; w <= width; w++) - for (int h = 0; h <= length; h++) - { - wall[w, h] = true; - } - - GridNode.maxX = width; - GridNode.maxY = length; - //Make a Stack - Stack s = new Stack(width * length); - //Random rand = new Random(DateTime.Now.Millisecond);//ha yeah randomized :P - //lets begin in the lower left corner eh?(0,0) - s.Push(new GridNode(0, 0)); - wall[0, 0] = false; - while (true) { - GridNode node = s.Peek(); - if (node.turnsPossible()) { - GridNode[] nodearray = node.getRandomNext(); - wall[nodearray[0].X, nodearray[0].Y] = false; - wall[nodearray[1].X, nodearray[1].Y] = false; - s.Push(nodearray[1]); - //we get the next two nodes - //the first is a middle node from which there shouldnt start a new corridor - //the second is added to the stack. next try will be with this node - //i hope this will work this time... - } else { - s.Pop();//if this node is a dead and it will be removed - } - if (s.Count < 1) break;//if no nodes are free anymore we will end the generation here - } - - Player.SendMessage(p, "Maze is generated. now painting..."); - //seems to be there are no more moves possible - ushort minX = Min.X, minZ = Min.Z, maxX = Max.X, maxZ = Max.Z, y = Min.Y; - maxX++; maxZ++; - - for (ushort xx = 0; xx <= width; xx++) - for (ushort zz = 0; zz <= length; zz++) - if (wall[xx, zz]) - { - PlaceBlock(p, lvl, (ushort)(xx + minX + 1), y, (ushort)(zz + minZ + 1), Block.staircasefull, 0); - PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 1), (ushort)(zz + minZ + 1), Block.leaf, 0); - PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 2), (ushort)(zz + minZ + 1), Block.leaf, 0); - } - - brush = new SolidBrush(Block.staircasefull, 0); - QuadX(minX, y, minZ, y, maxZ, p, lvl, brush); - QuadX(maxX, y, minZ, y, maxZ, p, lvl, brush); - QuadZ(minZ, y, minX, y, maxX, p, lvl, brush); - QuadZ(maxZ, y, minX, y, maxX, p, lvl, brush); - - brush = new SolidBrush(Block.leaf, 0); - QuadX(minX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); - QuadX(maxX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); - QuadZ(minZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush); - QuadZ(maxZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush); - + + public class MazeDrawOp : CuboidHollowsDrawOp { + + public override string Name { get { return "Maze"; } } + + internal int randomizer = 0; + bool[,] wall; + RNGCryptoServiceProvider rng1; + Random rng2; + byte[] r = new byte[1]; + int width, length; + + public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) { + int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2; + int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2; + return lenX * lenZ * 3; + } + + public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) { + width = Max.X - Min.X; + if (width % 2 != 0) { width++; Min.X--; } + width -= 2; + length = Max.Z - Min.Z; + if (length % 2 != 0) { length++; Min.Z--; } + length -= 2; + + if (width <= 0 || length <= 0) { + Player.SendMessage(p, "The corners of the maze need to be further apart."); return; + } + Player.SendMessage(p, "Generating maze... this could take a while"); + //substract 2 cause we will just make the inner. the outer wall is made seperately + wall = new bool[width + 1, length + 1];//+1 cause we begin at 0 so we need one object more + for (int w = 0; w <= width; w++) + for (int h = 0; h <= length; h++) + { + wall[w, h] = true; + } + rng1 = new RNGCryptoServiceProvider(); + rng2 = new Random(); + + Stack stack = new Stack(width * length); + stack.Push(new GridNode(0, 0)); + wall[0, 0] = false; + while (true) { + GridNode P = stack.Peek(); + if (TurnsPossible(P)) { + GridNode P1, P2; + MoveRandomDir(P, out P1, out P2); + wall[P1.X, P1.Y] = false; + wall[P2.X, P2.Y] = false; + stack.Push(P2); + //we get the next two nodes + //the first is a middle node from which there shouldnt start a new corridor + //the second is added to the stack. next try will be with this node + //i hope this will work this time... + } else { + stack.Pop();//if this node is a dead and it will be removed + } + if (stack.Count < 1) break;//if no nodes are free anymore we will end the generation here + } + + Player.SendMessage(p, "Generated maze, now drawing."); + ushort minX = Min.X, minZ = Min.Z, maxX = Max.X, maxZ = Max.Z, y = Min.Y; + for (ushort xx = 0; xx <= width; xx++) + for (ushort zz = 0; zz <= length; zz++) + if (wall[xx, zz]) + { + PlaceBlock(p, lvl, (ushort)(xx + minX + 1), y, (ushort)(zz + minZ + 1), Block.staircasefull, 0); + PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 1), (ushort)(zz + minZ + 1), Block.leaf, 0); + PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 2), (ushort)(zz + minZ + 1), Block.leaf, 0); + } + + brush = new SolidBrush(Block.staircasefull, 0); + QuadX(minX, y, minZ, y, maxZ, p, lvl, brush); + QuadX(maxX, y, minZ, y, maxZ, p, lvl, brush); + QuadZ(minZ, y, minX, y, maxX, p, lvl, brush); + QuadZ(maxZ, y, minX, y, maxX, p, lvl, brush); + + brush = new SolidBrush(Block.leaf, 0); + QuadX(minX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); + QuadX(maxX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); + QuadZ(minZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush); + QuadZ(maxZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush); + Player.SendMessage(p, "Maze painted. Build your entrance and exit yourself"); randomizer = 0; } - private class GridNode - { - public static int maxX = 0; - public static int maxY = 0; - public ushort X; - public ushort Y; - private Random rand2 = new Random(Environment.TickCount); - - public GridNode[] getRandomNext() { - byte[] r = new byte[1]; - switch (randomizer) { - case 0: - RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider(); - rand.GetBytes(r); - r[0] /= (255 / 4); - break; - default: - r[0] = (byte)rand2.Next(4); - break; - } - ushort rx = 0, ry = 0, rx2 = 0, ry2 = 0; - switch (r[0]) { - case 0: //go up - if (isWall(X, Y + 2)) { - rx = X; - rx2 = X; - ry = (ushort)(Y + 1); - ry2 = (ushort)(Y + 2); - } else { - return this.getRandomNext(); - } - break; - case 1: //go down - if (isWall(X, Y - 2)) { - rx = X; - rx2 = X; - ry = (ushort)(Y - 1); - ry2 = (ushort)(Y - 2); - } else { - return this.getRandomNext(); - } - break; - case 2: //go right - if (isWall(X + 2, Y)) { - rx = (ushort)(X + 1); - rx2 = (ushort)(X + 2); - ry = Y; - ry2 = Y; - } else { - return this.getRandomNext(); - } - break; - case 3: - if (isWall(X - 2, Y)) { - //go left - rx = (ushort)(X - 1); - rx2 = (ushort)(X - 2); - ry = Y; - ry2 = Y; - } else { - return this.getRandomNext(); - } - break; - } - return new GridNode[] { new GridNode(rx, ry), new GridNode(rx2, ry2) }; - } - - public bool turnsPossible() { - return (isWall(X, Y + 2) || isWall(X, Y - 2) || isWall(X + 2, Y) || isWall(X - 2, Y)); - } + void MoveRandomDir(GridNode P, out GridNode P1, out GridNode P2) { + while (true) { + r[0] = 0; + if (randomizer == 0) { + rng1.GetBytes(r); + r[0] /= (255 / 4); + } else { + r[0] = (byte)rng2.Next(4); + } - private bool isWall(int x, int y) { - try { - return wall[x, y]; - } catch (IndexOutOfRangeException) { - return false; - } - } - - public GridNode(ushort x, ushort y) { - X = x; Y = y; - } - } - } + switch (r[0]) { + case 0: //go up + if (IsWall(P.X, P.Y + 2)) { + P1 = new GridNode(P.X, (ushort)(P.Y + 1)); + P2 = new GridNode(P.X, (ushort)(P.Y + 2)); + return; + } break; + case 1: //go down + if (IsWall(P.X, P.Y - 2)) { + P1 = new GridNode(P.X, (ushort)(P.Y - 1)); + P2 = new GridNode(P.X, (ushort)(P.Y - 2)); + return; + } break; + case 2: //go right + if (IsWall(P.X + 2, P.Y)) { + P1 = new GridNode((ushort)(P.X + 1), P.Y); + P2 = new GridNode((ushort)(P.X + 2), P.Y); + return; + } break; + case 3: //go left + if (IsWall(P.X - 2, P.Y)) { + P1 = new GridNode((ushort)(P.X - 1), P.Y); + P2 = new GridNode((ushort)(P.X - 2), P.Y); + return; + } break; + } + } + } + + bool TurnsPossible(GridNode P) { + return IsWall(P.X, P.Y + 2) || IsWall(P.X, P.Y - 2) + || IsWall(P.X + 2, P.Y) || IsWall(P.X - 2, P.Y); + } + + bool IsWall(int x, int y) { + if (x < 0 || y < 0 || x >= width || y >= length) return false; + return wall[x, y]; + } + + struct GridNode { + public ushort X, Y; + + public GridNode(ushort x, ushort y) { + X = x; Y = y; + } + } + } }