public static TronicSequence StartFromProxy(N8BlockFactory Blocks = null, string name = "Proxy")
        {
            TronicSequence ts = new TronicSequence(Blocks);
            ts.Proxy(name);

            return ts;
        }
        public static TronicSequence StartFromButton(N8BlockFactory Blocks = null, int type = 1, string name = "Button")
        {
            TronicSequence ts = new TronicSequence(Blocks);
            ts.Button(type, name);

            return ts;
        }
        public static TronicSequence StartFromReciever(DataNodeIn Channel, DataNodeOut Username, DataNodeOut Message, N8BlockFactory Blocks = null, string name = "Reciever")
        {
            TronicSequence ts = new TronicSequence(Blocks);
            ts.Button(1, "Reciever Setup")
              .RadioReciever(Channel, Username, Message, name);

            return ts;
        }
 public TronicSequence(N8Tronic Initial, NodeType InitialOut = NodeType.FlowOutA)
 {
     data = new List<DataBlock>();
     tronics = new N8BlockFactory();
     CurrentTronic = (FlowTronic)Initial;
     CurrentOut = Initial.GetNode(InitialOut);
     sequence = new List<FlowTronic>();
     Branches = new Stack<Tuple<FlowTronic, Node>>();
 }
        public static TronicSequence GetMessageScreen(N8BlockFactory blocks = null, string separator = " === ")
        {
            TronicSequence ts = TronicSequence.StartFromKeyboard(blocks);
            DataBlock CurrentMessage = ts.data.First();
            DataBlock Separator = ts.NewDataBlock("Separator", separator);
            DataBlock MessageArchive = ts.NewDataBlock("MessageArchive", "Archive begins: ");

            ts.And(MessageArchive.In, Separator.In, MessageArchive.Out, "Separator Append")
              .And(MessageArchive.In, CurrentMessage.In, MessageArchive.Out, "Message Append")
              .Display(CurrentMessage.In, "Message Display");

            return ts;
        }
        public static TronicSequence StartFromKeyboard(N8BlockFactory Blocks = null, DataNodeOut DataOut = null, string name = "Keyboard")
        {
            TronicSequence ts = new TronicSequence(Blocks);
            //I just learned about the null coalsece operator! it is awesome.
            ts.Keyboard(DataOut ?? ts.NewDataBlock().Out, name);

            if (!ts.data.Contains(DataOut.Parent))
            {
                ts.data.Add(DataOut.Parent);
            }

            return ts;
        }
 public TronicSequence(N8BlockFactory blocks = null)
 {
     data = new List<DataBlock>();
     if (blocks == null)
     {
         tronics = new N8BlockFactory();
     }
     else
     {
         tronics = blocks;
     }
     sequence = new List<FlowTronic>();
     Branches = new Stack<Tuple<FlowTronic, Node>>();
 }
        public N8Level(string SavePath)
        {
            int lineNum = 0;
            blocks = new N8BlockFactory();
            if (!SavePath.EndsWith(".ncd"))
            {
                SavePath += ".ncd";
            }
            using (StreamReader sr = new StreamReader(File.OpenRead(SavePath)))
            {
                string input;

                //Parse blocks
                while ((input = sr.ReadLine()) != "tronics" && input != null)
                {
                    lineNum++;
                    blocks.AddBlockFromSave(input);
                }

                //Parse tronics (not sure why they're different, the format is the same
                //But Aion put them in their own section so I'll do the same
                while ((input = sr.ReadLine()) != "attach" && input != null)
                {
                    lineNum++;
                    blocks.AddTronicFromSave(input);
                }

                //Parse attachments
                while ((input = sr.ReadLine()) != "wire" && input != null)
                {
                    lineNum++;
                    N8Block Attachee;
                    N8Block Attacher;
                    int AttacheeID = int.Parse(input.Split(':')[0]);
                    int AttacherID = int.Parse(input.Split(':')[1]);

                    bool foundAttachee = blocks.GetItem(AttacheeID, out Attachee);
                    bool foundAttacher = blocks.GetItem(AttacherID, out Attacher);

                    if (!foundAttachee || !foundAttacher) //Screw you DeMorgan!
                    {
                        string message = "I found you an attachment warning but I forgotted it";

                        if (!foundAttachee)
                        {
                            message = "Could not find attachee, id = " + AttacheeID;
                        }
                        if (!foundAttacher)
                        {
                            message = "Could not find attacher, id = " + AttacherID + "; this is probably the shrine unless it happens with more than one ID";
                        }
                        if (!foundAttacher && !foundAttachee)
                        {
                            message = "Could not find either attacher, id = " + AttacherID + " or attachee, id = " + AttacheeID;
                        }

                        warn(message, lineNum);

                        //If it's just the attacher and not the attachee, this is probably stuff that was attached to the shrine.
                        //Make a fake block for it.

                        if (foundAttachee && !foundAttacher)
                        {
                            Attacher = blocks.GenerateShrine(AttacherID);
                        }
                        else
                        {
                            continue;
                        }
                    }

                    //Found the attacher and the attachee, do eeit.
                    Attacher.AttachToMe(Attachee);
                }

                //And then do the wires
                while ((input = sr.ReadLine()) != null)
                {
                    lineNum++;

                    string[] parts = input.Split(',');
                    bool FoundLeft;
                    N8Tronic Left;
                    int LeftID = int.Parse(parts[0]);
                    NodeType LeftNode = (NodeType)int.Parse(parts[1]);

                    bool FoundRight;
                    N8Tronic Right;
                    int RightID = int.Parse(parts[2]);
                    NodeType RightNode = (NodeType) int.Parse(parts[3]);

                    //only tronics have wires, so only look in the tronics
                    FoundLeft = blocks.GetTronic(LeftID, out Left);
                    FoundRight = blocks.GetTronic(RightID, out Right);

                    if (!FoundRight || !FoundLeft)
                    {
                        string message = "I found you a wire warning but I forgotted it";

                        if (!FoundRight)
                        {
                            message = "Could not find tronic id = " + RightID;
                        }
                        if (!FoundLeft)
                        {
                            message = "Could not find tronic id = " + LeftID;
                        }
                        if (!FoundLeft && !FoundRight)
                        {
                            message = "Could not find tronic id = " + LeftID + " or id = " + RightID;
                        }

                        warn(message, lineNum);
                        continue;
                    }
                    Left.WireTo(Left.GetNode(LeftNode), Right.GetNode(RightNode));
                }
            }
        }
 public N8Level()
 {
     blocks = new N8BlockFactory();
 }
        private static Tuple<Rotor, Rotor, N8Block> GenerateUnit(N8BlockFactory blocks, string blocktype, string blockname)
        {
            N8Block UnitBase = blocks.GenerateBlock(blocktype, blockname);
            Rotor reset = blocks.Rotor("Reset");
            Rotor fall = blocks.Rotor("Fall");
            Target t = blocks.Target("Hit me!");

            UnitBase.rotation = new Quaternion(new Vector3D(0, 0, 1), -90);

            t.FlowOutTo(fall);
            t.position.Z = 67;
            t.position.X = 2;
            t.rotation = new Quaternion(new Vector3D(0, 0, 1), -90) * new Quaternion(new Vector3D(0, 1, 0), 90);
            fall.position.X = 2;
            fall.position.Z = 5;

            fall.rotation = new Quaternion(new Vector3D(0, 1, 0), 90);

            UnitBase.AttachToMe(reset);
            UnitBase.AttachToMe(fall);
            UnitBase.AttachToMe(t);

            return Tuple.Create(reset, fall, UnitBase);
        }
        private static void FleeTronics(N8BlockFactory LevelBlocks, List<FlowTronic> alerts, bool rotate = true, bool AttachLevelBlocks = false, string password = null)
        {
            Quaternion UpsideDown = new Quaternion(new Vector3D(1, 0, 0), 180);

            FlowTronic InitTronic;
            if (password == null)
            {
                InitTronic = LevelBlocks.Keyboard("Set Cell Password");
                InitTronic.position = new Vector3D(30, -30, 5);
            }
            else
            {
                InitTronic = LevelBlocks.Button(1, "Setup Reciever");
            }

            TronicSequence Reciever = new TronicSequence(InitTronic);

            DataBlock Channel = Reciever.NewDataBlock("Channel", "1025");
            DataBlock UsernameRec = Reciever.NewDataBlock("Recieved Username");
            DataBlock MessageRec = Reciever.NewDataBlock("Recieved Message");

            DataBlock UsernameStore = Reciever.NewDataBlock("Stored Username", "Tacroy");
            //Not used atm
            //DataBlock AlternateUsernameStore = Reciever.NewDataBlock("Alternate Username", "nobody");
            DataBlock Password = Reciever.NewDataBlock("Password", password ?? "");
            if (password == null)
            {
                InitTronic.DataOutA(Password.Out);
            }

            Reciever.RadioReciever(Channel.In, UsernameRec.Out, MessageRec.Out);

            TronicSequence PasswordTest = new TronicSequence();

            PasswordTest.IfEqual(Password.In, MessageRec.In, "PasswordCheck");

            TronicSequence NameTest = new TronicSequence();

            NameTest.IfEqual(UsernameRec.In, UsernameStore.In, "NameCheck");

            TronicSequence FlipFlop = TronicsTesting.Ringbuffer(new List<string>(new string[] { "0", "1" }));
            DataBlock ControlBit = FlipFlop.data[FlipFlop.data.Count - 1];
            DataBlock ReturnPos = Reciever.NewDataBlock("Return Position", "v0,0,0");

            Reciever.Append(NameTest)
                    .Append(PasswordTest)
                    .Append(FlipFlop)
                    .Mover(ReturnPos.In, ReturnPos.Out, "Return Mover")
                    .RadioTransmit(Channel.In, ControlBit.In, "Yeller");

            TronicSequence RandomBottomVector = TronicsTesting.RandomXYVectorGenerator(-1000, 1000, -1000);
            TronicSequence RandomTopVector = TronicsTesting.RandomXYVectorGenerator(-2000, 2000, 2000);
            DataBlock RandVectTop = RandomTopVector.data[RandomTopVector.data.Count - 1];
            DataBlock RandVectBottom = RandomBottomVector.data[RandomBottomVector.data.Count - 1];

            Random rand = new Random();

            Vector3D AttachOffset = rand.NextVector(new Vector3D(60,60,0), new Vector3D(-60,-60,0));

            foreach (FlowTronic alert in alerts)
            {
                alert.position += AttachOffset;
                RandomTopVector.GetFirst().FlowInFrom(alert);
            }

            N8Block TronicAttach = LevelBlocks.GenerateBlock("letter.period", "Attach Point");
            TronicAttach.position = -AttachOffset;
            TronicAttach.position.Z = 500;

            TronicSequence MovementLogic = new TronicSequence();
            MovementLogic.Append(RandomTopVector);

            MovementLogic.IfGreater(ControlBit.In, null, "Control");

            if (rotate)
            {
                TronicSequence ProxyRotor = new TronicSequence();
                DataBlock Quantity = ProxyRotor.NewDataBlock("Amount", "q0,0,1,0");
                DataBlock Current = ProxyRotor.NewDataBlock("Current", "q1,0,0,0");

                ProxyRotor.Multiply(Quantity.In, Current.In, Current.Out, "Unit step")
                          .Rotor(Current.In, null, "Rotate1");
                MovementLogic.Append(ProxyRotor);
            }
            //Mega and vacubombs take 15 seconds to explode, regular 10. Add 2 seconds up in the sky for a buffer.
            //Also keep in mind that because we fly up then delay, once we're up there we're a random sky mover so that should be safe enough.
            DataBlock DelayTime = MovementLogic.NewDataBlock("Delay", "17");
            MovementLogic.Mover(RandVectTop.In, null, "Flee Mover 1")
                         .Delay(DelayTime.In)
                         .Append(RandomBottomVector)
                         .Mover(RandVectBottom.In, null, "Flee Mover 2");

            MovementLogic.GetCurrent().Item1.FlowOutTo((FlowTronic)Reciever.tronics.Tronics.Last());

            MovementLogic.LayoutDense(AttachOffset);
            Reciever.LayoutDense(AttachOffset);

            //Attach everything
            Reciever.AttachAllNonPositional(TronicAttach, false);
            MovementLogic.AttachAllNonPositional(TronicAttach, false);

            foreach (N8Tronic t in alerts)
            {
                TronicAttach.AttachToMe(t);
            }

            LevelBlocks.CopyFromDestructive(MovementLogic.tronics);
            LevelBlocks.CopyFromDestructive(Reciever.tronics);

            if (AttachLevelBlocks)
            {
                foreach (N8Block b in from N8Block t in LevelBlocks.Blocks where t.name != "Attach Point" select t)
                {
                    b.position += AttachOffset;
                    TronicAttach.AttachToMe(b);
                }
            }

            N8Tronic RetMover = (from N8Tronic t in LevelBlocks.Tronics where t.name == "Return Mover" select t).First();
            N8Tronic FleeMover1 = (from N8Tronic t in LevelBlocks.Tronics where t.name == "Flee Mover 1" select t).First();
            N8Tronic FleeMover2 = (from N8Tronic t in LevelBlocks.Tronics where t.name == "Flee Mover 2" select t).First();

            RetMover.position.Z = -1000;
            FleeMover1.position.Z = 0;
            FleeMover1.position.X = -30;
            FleeMover2.position.Z = 0;
            FleeMover2.position.X = 30;
            RetMover.Detach();
            FleeMover1.Detach();
            FleeMover2.Detach();

            if (rotate)
            {
                N8Tronic Rotor = (from N8Tronic t in LevelBlocks.Tronics where t.name == "Rotate1" select t).First();
                TronicAttach.AttachToMe(Rotor);
            }

            Console.WriteLine("Total block count: " + (LevelBlocks.Blocks.Count + LevelBlocks.Tronics.Count));
        }