The maze command is now a drawop.

This commit is contained in:
UnknownShadow200 2016-03-22 10:43:59 +11:00
parent 61183a60f6
commit 2353897f3a
5 changed files with 221 additions and 225 deletions

View File

@ -31,240 +31,37 @@ namespace MCGalaxy.Commands
public override string type { get { return CommandTypes.Building; } }
public override bool museumUsable { get { return false; } }
public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } }
public static int randomizer = 0;
public static bool[,] wall;
public override void Use(Player p, string message) {
if (message.Length > 0 && !int.TryParse(message, out randomizer)) {
if (message.Length > 0 && !int.TryParse(message, out MazeDrawOp.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.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 CatchPos(x, y, z);
p.blockchangeObject = new Vector3U16(x, y, z);
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 first = (CatchPos)p.blockchangeObject;
int width = Math.Max(x, first.X) - Math.Min(x, first.X);
if (width % 2 != 0) { width++;x--; }
width -= 2;
int height = Math.Max(z, first.Z) - Math.Min(z, first.Z);
if (height % 2 != 0) { height++;z--; }
height -= 2;
if (width < 0 || height < 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, height+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 <= height; h++)
{
wall[w, h] = true;
}
}
GridNode.maxX = width;
GridNode.maxY = height;
//Make a Stack
Stack s = new Stack(width * height);
//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 = (GridNode)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
//paint that shit :P
ushort minX = Math.Min(x, first.X);
ushort minZ = Math.Min(z, first.Z);
ushort maxX = Math.Max(x, first.X);
maxX++;
ushort maxZ = Math.Max(z, first.Z);
maxZ++;
for (ushort xx = 0; xx <= width; xx++)
{
for (ushort zz = 0; zz <= height; zz++)
{
if (wall[xx, zz])
{
p.level.UpdateBlock(p, (ushort)(xx + minX+1), y, (ushort)(zz + minZ+1), Block.staircasefull, 0);
p.level.UpdateBlock(p, (ushort)(xx + minX+1), (ushort)(y + 1), (ushort)(zz + minZ+1), Block.leaf, 0);
p.level.UpdateBlock(p, (ushort)(xx + minX+1), (ushort)(y + 2), (ushort)(zz + minZ+1), Block.leaf, 0);
}
}
}
CuboidWallsDrawOp drawOp = new CuboidWallsDrawOp();
drawOp.method = DrawOp.MethodBlockChange;
SolidBrush brush = new SolidBrush(Block.staircasefull, 0);
Vector3U16[] marks = { new Vector3U16(minX, y, minZ), new Vector3U16(maxX, y, maxZ) };
drawOp.Perform(marks, p, p.level, brush);
brush = new SolidBrush(Block.leaf, 0);
marks[0].Y = (ushort)(y + 1); marks[1].Y = (ushort)(y + 2);
drawOp.Perform(marks, p, p.level, brush);
Player.SendMessage(p, "Maze painted. Build your entrance and exit yourself");
randomizer = 0;
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);
}
public override void Help(Player p) {
Player.SendMessage(p, "/maze: generates a maze");
}
private class CatchPos
{
public ushort X;
public ushort Y;
public ushort Z;
//public byte type;
public CatchPos(ushort x, ushort y, ushort z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
}
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:
if (isWall(X, Y + 2))
{
//go up
rx = X;
rx2 = X;
ry = (ushort)(Y + 1);
ry2 = (ushort)(Y + 2);
}
else
{
return this.getRandomNext();
}
break;
case 1:
if (isWall(X, Y - 2))
{
//go down
rx = X;
rx2 = X;
ry = (ushort)(Y - 1);
ry2 = (ushort)(Y - 2);
}
else
{
return this.getRandomNext();
}
break;
case 2:
if (isWall(X + 2, Y))
{
//go right
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));
}
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;
}
Player.SendMessage(p, "%T/maze");
Player.SendMessage(p, "%HGenerates a random maze between two points.");
}
}
}

View File

@ -135,9 +135,10 @@ namespace MCGalaxy.Commands
Player.SendMessage(p, "You can only undo physics if you can use /physics."); return;
}
Command.all.Find("physics").Use(p, "0");
UndoPhysicsDrawOp drawOp = new UndoPhysicsDrawOp();
drawOp.seconds = seconds;
drawOp.Perform(null, p, p.level, null);
UndoPhysicsDrawOp op = new UndoPhysicsDrawOp();
op.seconds = seconds;
op.Perform(null, p, p.level, null);
Player.GlobalMessage("Physics were undone &b" + seconds + " %Sseconds");
Server.s.Log( "Physics were undone &b" + seconds + " %Sseconds");
p.level.Save(true);

View File

@ -63,10 +63,10 @@ namespace MCGalaxy.Drawing.Ops {
QuadX(p2.X, (ushort)(p1.Y + 1), p1.Z, (ushort)(p2.Y - 1), p2.Z, p, lvl, brush);
}
if (lenX > 2 && lenY > 2) {
QuadZ(p1.Z, (ushort)(p1.X + 1), (ushort)(p1.Y + 1),
(ushort)(p2.X - 1), (ushort)(p2.Y - 1), p, lvl, brush);
QuadZ(p2.Z, (ushort)(p1.X + 1), (ushort)(p1.Y + 1),
(ushort)(p2.X - 1), (ushort)(p2.Y - 1), p, lvl, brush);
QuadZ(p1.Z, (ushort)(p1.Y + 1), (ushort)(p1.X + 1),
(ushort)(p2.Y - 1), (ushort)(p2.X - 1), p, lvl, brush);
QuadZ(p2.Z, (ushort)(p1.Y + 1), (ushort)(p1.X + 1),
(ushort)(p2.Y - 1), (ushort)(p2.X - 1), p, lvl, brush);
}
}
@ -88,7 +88,7 @@ namespace MCGalaxy.Drawing.Ops {
}
}
protected void QuadZ(ushort z, ushort x1, ushort y1, ushort x2, ushort y2,
protected void QuadZ(ushort z, ushort y1, ushort x1, ushort y2, ushort x2,
Player p, Level lvl, Brush brush) {
for (ushort y = y1; y <= y2; y++)
for (ushort x = x1; x <= x2; x++)
@ -116,8 +116,8 @@ namespace MCGalaxy.Drawing.Ops {
QuadX(p1.X, p1.Y, p1.Z, p2.Y, p2.Z, p, lvl, brush);
QuadX(p2.X, p1.Y, p1.Z, p2.Y, p2.Z, p, lvl, brush);
if (lenX > 2) {
QuadZ(p1.Z, (ushort)(p1.X + 1), p1.Y, (ushort)(p2.X - 1), p2.Y, p, lvl, brush);
QuadZ(p2.Z, (ushort)(p1.X + 1), p1.Y, (ushort)(p2.X - 1), p2.Y, p, lvl, brush);
QuadZ(p1.Z, p1.Y, (ushort)(p1.X + 1), p2.Y, (ushort)(p2.X - 1), p, lvl, brush);
QuadZ(p2.Z, p1.Y, (ushort)(p1.X + 1), p2.Y, (ushort)(p2.X - 1), p, lvl, brush);
}
}
}

View File

@ -0,0 +1,197 @@
/*
Copyright 2011 MCForge
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
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<GridNode> s = new Stack<GridNode>(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);
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));
}
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;
}
}
}
}

View File

@ -406,6 +406,7 @@
<Compile Include="Drawing\DrawOps\DrawOp.cs" />
<Compile Include="Drawing\DrawOps\FillDrawOp.cs" />
<Compile Include="Drawing\DrawOps\LineDrawOp.cs" />
<Compile Include="Drawing\DrawOps\MazeDrawOp.cs" />
<Compile Include="Drawing\DrawOps\PasteDrawOp.cs" />
<Compile Include="Drawing\DrawOps\ReplaceDrawOp.cs" />
<Compile Include="Drawing\DrawOps\SpheroidDrawOp.cs" />