Example #1
0
        protected override void LoadContent()
        {
            if (this.firstLoadContentCall)
            {
                // First time loading content. Create the renderer.
                this.LightingManager = new LightingManager();
                this.AddComponent(this.LightingManager);
                this.Renderer = new Renderer(this, this.ScreenSize, true, true, false);

                this.AddComponent(this.Renderer);
                this.renderParameters = new RenderParameters
                {
                    Camera = this.Camera,
                    IsMainRender = true
                };
                this.firstLoadContentCall = false;

                this.UI = new UIRenderer();
                this.AddComponent(this.UI);

            #if PERFORMANCE_MONITOR
                ListContainer performanceMonitor = new ListContainer();
                performanceMonitor.Add(new Binding<Vector2, Point>(performanceMonitor.Position, x => new Vector2(0, x.Y), this.ScreenSize));
                performanceMonitor.AnchorPoint.Value = new Vector2(0, 1);
                performanceMonitor.Visible.Value = false;
                performanceMonitor.Name.Value = "PerformanceMonitor";
                this.UI.Root.Children.Add(performanceMonitor);

                Action<string, Property<double>> addLabel = delegate(string label, Property<double> property)
                {
                    TextElement text = new TextElement();
                    text.FontFile.Value = "Font";
                    text.Add(new Binding<string, double>(text.Text, x => label + ": " + (x * 1000.0).ToString("F") + "ms", property));
                    performanceMonitor.Children.Add(text);
                };

                TextElement frameRateText = new TextElement();
                frameRateText.FontFile.Value = "Font";
                frameRateText.Add(new Binding<string, float>(frameRateText.Text, x => "FPS: " + x.ToString("0"), this.frameRate));
                performanceMonitor.Children.Add(frameRateText);

                addLabel("Physics", this.physicsTime);
                addLabel("Update", this.updateTime);
                addLabel("Pre-frame", this.preframeTime);
                addLabel("Raw render", this.rawRenderTime);
                addLabel("Shadow render", this.shadowRenderTime);
                addLabel("Post-process", this.postProcessTime);

                PCInput input = new PCInput();
                input.Add(new CommandBinding(input.GetChord(new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.P }), delegate()
                {
                    performanceMonitor.Visible.Value = !performanceMonitor.Visible;
                }));
                this.AddComponent(input);
            #endif

                IEnumerable<string> globalStaticScripts = Directory.GetFiles(Path.Combine(this.Content.RootDirectory, "Maps", "GlobalStaticScripts"), "*", SearchOption.AllDirectories).Select(x => Path.Combine("Maps", "GlobalStaticScripts", Path.GetFileNameWithoutExtension(x)));
                foreach (string scriptName in globalStaticScripts)
                    this.executeStaticScript(scriptName);
            }
            else
            {
                foreach (IComponent c in this.components)
                    c.LoadContent(true);
                this.ReloadedContent.Execute();
            }
        }
Example #2
0
        public override Entity Create(Main main)
        {
            Entity result = new Entity(main, "Editor");
            result.Serialize = false;
            Editor editor = new Editor();
            EditorUI ui = new EditorUI { Editable = false };
            Model model = new Model { Editable = false, Filename = new Property<string> { Value = "Models\\selector" }, Scale = new Property<Vector3> { Value = new Vector3(0.5f) } };

            UIRenderer uiRenderer = new UIRenderer { Editable = false };
            FPSInput input = new FPSInput { Editable = false };
            input.EnabledWhenPaused.Value = true;
            AudioListener audioListener = new AudioListener { Editable = false };

            Scroller scroller = new Scroller();
            scroller.Position.Value = new Vector2(10, 10);
            scroller.AnchorPoint.Value = new Vector2(0, 0);
            scroller.ResizeHorizontal.Value = true;
            scroller.Name.Value = "Scroller";
            uiRenderer.Root.Children.Add(scroller);

            ListContainer uiList = new ListContainer();
            uiList.Name.Value = "PropertyList";
            uiList.AnchorPoint.Value = new Vector2(0, 0);
            scroller.Children.Add(uiList);

            Container popup = new Container();
            popup.Name.Value = "Popup";
            popup.Opacity.Value = 0.5f;
            popup.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            uiRenderer.Root.Children.Add(popup);

            ListContainer popupLayout = new ListContainer();
            popup.Children.Add(popupLayout);

            Container popupSearchContainer = new Container();
            popupSearchContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            popupLayout.Children.Add(popupSearchContainer);

            TextElement popupSearch = new TextElement();
            popupSearch.Name.Value = "PopupSearch";
            popupSearch.FontFile.Value = "Font";
            popupSearchContainer.Children.Add(popupSearch);

            Scroller popupScroller = new Scroller();
            popupScroller.Size.Value = new Vector2(200.0f, 300.0f);
            popupLayout.Children.Add(popupScroller);

            ListContainer popupList = new ListContainer();
            popupList.Name.Value = "PopupList";
            popupScroller.Children.Add(popupList);

            result.Add("Editor", editor);
            result.Add("UI", ui);
            result.Add("UIRenderer", uiRenderer);
            result.Add("Model", model);
            result.Add("Input", input);
            result.Add("AudioListener", audioListener);
            result.Add("StartSpawnPoint", new Property<string>());
            result.Add("ProceduralGenerator", new ProceduralGenerator());

            return result;
        }
Example #3
0
		public static void Attach(Main main, Entity result, AnimatedModel model, FPSInput input, Phone phone, Property<bool> enableWalking, Property<bool> enableMoves)
		{
			Property<bool> phoneActive = result.GetOrMakeProperty<bool>("PhoneActive");
			Property<bool> noteActive = result.GetOrMakeProperty<bool>("NoteActive");

			UIRenderer phoneUi = result.GetOrCreate<UIRenderer>("PhoneUI");

			Property<Entity.Handle> signalTower = result.GetOrMakeProperty<Entity.Handle>("SignalTower");

			const float phoneWidth = 200.0f;

			phoneUi.RenderTargetBackground.Value = Microsoft.Xna.Framework.Color.White;
			phoneUi.RenderTargetSize.Value = new Point((int)phoneWidth, (int)(phoneWidth * 2.0f));
			phoneUi.Serialize = false;
			phoneUi.Enabled.Value = false;

			Model phoneModel = result.GetOrCreate<Model>("PhoneModel");
			phoneModel.Filename.Value = "Models\\phone";
			phoneModel.Color.Value = new Vector3(0.13f, 0.13f, 0.13f);
			phoneModel.Serialize = false;
			phoneModel.Enabled.Value = false;

			Property<Matrix> phoneBone = model.GetBoneTransform("Phone");
			phoneModel.Add(new Binding<Matrix>(phoneModel.Transform, () => phoneBone.Value * model.Transform, phoneBone, model.Transform));

			Model screen = result.GetOrCreate<Model>("Screen");
			screen.Filename.Value = "Models\\plane";
			screen.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(screen.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), phoneUi.RenderTarget));
			screen.Add(new Binding<Matrix>(screen.Transform, x => Matrix.CreateTranslation(0.015f, 0.0f, 0.0f) * x, phoneModel.Transform));
			screen.Serialize = false;
			screen.Enabled.Value = false;

			PointLight phoneLight = result.GetOrCreate<PointLight>("PhoneLight");
			phoneLight.Serialize = false;
			phoneLight.Enabled.Value = false;
			phoneLight.Attenuation.Value = 0.5f;
			phoneLight.Add(new Binding<Vector3, Matrix>(phoneLight.Position, x => x.Translation, screen.Transform));

			const float screenScale = 0.0007f;
			screen.Scale.Value = new Vector3(1.0f, (float)phoneUi.RenderTargetSize.Value.Y * screenScale, (float)phoneUi.RenderTargetSize.Value.X * screenScale);

			// Transform screen space mouse position into 3D, then back into the 2D space of the phone UI
			Property<Matrix> screenTransform = new Property<Matrix>();
			screen.Add(new Binding<Matrix>(screenTransform, () => Matrix.CreateScale(screen.Scale) * screen.Transform, screen.Scale, screen.Transform));
			phoneUi.Setup3D(screenTransform);

			// Phone UI

			const float padding = 8.0f;
			const float messageWidth = phoneWidth - padding * 2.0f;

			Func<Color, string, float, Container> makeButton = delegate(Color color, string text, float width)
			{
				Container bg = new Container();
				bg.Tint.Value = color;
				bg.PaddingBottom.Value = bg.PaddingLeft.Value = bg.PaddingRight.Value = bg.PaddingTop.Value = padding * 0.5f;
				Color highlightColor = new Color(color.ToVector4() + new Vector4(0.2f, 0.2f, 0.2f, 0.0f));
				bg.Add(new Binding<Color, bool>(bg.Tint, x => x ? highlightColor : color, bg.Highlighted));

				TextElement msg = new TextElement();
				msg.Name.Value = "Text";
				msg.FontFile.Value = "Font";
				msg.Text.Value = text;
				msg.WrapWidth.Value = width;
				bg.Children.Add(msg);
				return bg;
			};

			Func<UIComponent, bool, Container> makeAlign = delegate(UIComponent component, bool right)
			{
				Container container = new Container();
				container.Opacity.Value = 0.0f;
				container.PaddingBottom.Value = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 0.0f;
				container.ResizeHorizontal.Value = false;
				container.Size.Value = new Vector2(messageWidth, 0.0f);
				component.AnchorPoint.Value = new Vector2(right ? 1.0f : 0.0f, 0.0f);
				component.Position.Value = new Vector2(right ? messageWidth : 0.0f, 0.0f);
				container.Children.Add(component);
				return container;
			};

			Color incomingColor = new Color(0.0f, 0.0f, 0.0f, 1.0f);
			Color outgoingColor = new Color(0.0f, 0.175f, 0.35f, 1.0f);

			Container topBarContainer = new Container();
			topBarContainer.ResizeHorizontal.Value = false;
			topBarContainer.Size.Value = new Vector2(phoneUi.RenderTargetSize.Value.X, 0.0f);
			topBarContainer.Tint.Value = new Color(0.15f, 0.15f, 0.15f, 1.0f);
			phoneUi.Root.Children.Add(topBarContainer);

			ListContainer phoneTopBar = new ListContainer();
			phoneTopBar.Orientation.Value = ListContainer.ListOrientation.Horizontal;
			phoneTopBar.Spacing.Value = padding;
			topBarContainer.Children.Add(phoneTopBar);

			Sprite signalIcon = new Sprite();
			signalIcon.Image.Value = "Images\\signal";
			phoneTopBar.Children.Add(signalIcon);

			TextElement noService = new TextElement();
			noService.FontFile.Value = "Font";
			noService.Text.Value = "\\no service";
			phoneTopBar.Children.Add(noService);

			signalIcon.Add(new Binding<bool, Entity.Handle>(signalIcon.Visible, x => x.Target != null && x.Target.Active, signalTower));
			noService.Add(new Binding<bool, Entity.Handle>(noService.Visible, x => x.Target == null || !x.Target.Active, signalTower));

			ListContainer phoneLayout = new ListContainer();
			phoneLayout.Spacing.Value = padding;
			phoneLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
			phoneLayout.Add(new Binding<Vector2>(phoneLayout.Position, x => new Vector2(padding, x.Y), topBarContainer.Size));
			phoneLayout.Add(new Binding<Vector2>(phoneLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X - padding * 2.0f, phoneUi.RenderTargetSize.Value.Y - padding - topBarContainer.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size));
			phoneUi.Root.Children.Add(phoneLayout);

			Container composeButton = makeButton(new Color(0.5f, 0.0f, 0.0f, 1.0f), "\\compose", messageWidth - padding * 2.0f);
			TextElement composeText = (TextElement)composeButton.GetChildByName("Text");
			composeText.Add(new Binding<string, bool>(composeText.Text, x => x ? "\\compose gamepad" : "\\compose", main.GamePadConnected));
			UIComponent composeAlign = makeAlign(composeButton, true);

			Scroller phoneScroll = new Scroller();
			phoneScroll.ResizeVertical.Value = false;
			phoneScroll.Add(new Binding<Vector2>(phoneScroll.Size, () => new Vector2(phoneLayout.Size.Value.X, phoneLayout.Size.Value.Y - phoneLayout.Spacing.Value - composeAlign.ScaledSize.Value.Y), phoneLayout.Size, phoneLayout.Spacing, composeAlign.ScaledSize));

			phoneLayout.Children.Add(phoneScroll);
			phoneLayout.Children.Add(composeAlign);

			ListContainer msgList = new ListContainer();
			msgList.Spacing.Value = padding * 0.5f;
			msgList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			msgList.ResizePerpendicular.Value = false;
			msgList.Size.Value = new Vector2(messageWidth, 0.0f);
			phoneScroll.Children.Add(msgList);

			Container answerContainer = new Container();
			answerContainer.PaddingBottom.Value = answerContainer.PaddingLeft.Value = answerContainer.PaddingRight.Value = answerContainer.PaddingTop.Value = padding;
			answerContainer.Tint.Value = incomingColor;
			answerContainer.AnchorPoint.Value = new Vector2(1.0f, 1.0f);
			answerContainer.Add(new Binding<Vector2>(answerContainer.Position, () => composeAlign.Position.Value + new Vector2(composeAlign.ScaledSize.Value.X + padding, padding * 3.0f), composeAlign.Position, composeAlign.ScaledSize));
			phoneUi.Root.Children.Add(answerContainer);
			answerContainer.Visible.Value = false;

			ListContainer answerList = new ListContainer();
			answerList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			answerList.Alignment.Value = ListContainer.ListAlignment.Max;
			answerContainer.Children.Add(answerList);

			int selectedAnswer = 0;

			composeButton.Add(new CommandBinding<Point>(composeButton.MouseLeftUp, delegate(Point p)
			{
				answerContainer.Visible.Value = !answerContainer.Visible;
				if (answerContainer.Visible && main.GamePadConnected)
				{
					selectedAnswer = 0;
					foreach (UIComponent answer in answerList.Children)
						answer.Highlighted.Value = false;
					answerList.Children[0].Highlighted.Value = true;
				}
			}));

			Action scrollToBottom = delegate()
			{
				// HACK
				main.AddComponent(new Animation
				(
					new Animation.Delay(0.01f),
					new Animation.Execute(delegate()
					{
						phoneScroll.ScrollToBottom();
					})
				));
			};

			// Note

			UIRenderer noteUi = result.GetOrCreate<UIRenderer>("NoteUI");

			const float noteWidth = 400.0f;
			const float noteScale = 0.0009f;

			noteUi.RenderTargetBackground.Value = new Microsoft.Xna.Framework.Color(1.0f, 0.95f, 0.9f);
			noteUi.RenderTargetSize.Value = new Point((int)noteWidth, (int)(noteWidth * 1.29f)); // 8.5x11 aspect ratio
			noteUi.Serialize = false;
			noteUi.Enabled.Value = false;

			Model noteModel = result.GetOrCreate<Model>("Note");
			noteModel.Filename.Value = "Models\\plane";
			noteModel.EffectFile.Value = "Effects\\Default";
			noteModel.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(noteModel.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), noteUi.RenderTarget));
			noteModel.Add(new Binding<Matrix>(noteModel.Transform, x => Matrix.CreateTranslation(-0.005f, 0.05f, 0.08f) * x, phoneModel.Transform));
			noteModel.Scale.Value = new Vector3(1.0f, (float)noteUi.RenderTargetSize.Value.Y * noteScale, (float)noteUi.RenderTargetSize.Value.X * noteScale);
			noteModel.Serialize = false;
			noteModel.Enabled.Value = false;
			Property<Entity.Handle> note = result.GetOrMakeProperty<Entity.Handle>("Note");

			Container togglePhoneMessage = null;

			result.Add(new NotifyBinding(delegate()
			{
				bool hasNoteOrSignalTower = (note.Value.Target != null && note.Value.Target.Active)
					|| (signalTower.Value.Target != null && signalTower.Value.Target.Active);

				if (togglePhoneMessage == null && hasNoteOrSignalTower)
					togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]");
				else if (togglePhoneMessage != null && !hasNoteOrSignalTower && !phoneActive && !noteActive)
				{
					((GameMain)main).Menu.HideMessage(result, togglePhoneMessage);
					togglePhoneMessage = null;
				}
			}, note, signalTower));

			result.Add(new CommandBinding(result.Delete, delegate()
			{
				((GameMain)main).Menu.HideMessage(null, togglePhoneMessage);
			}));

			// Note UI

			const float notePadding = 40.0f;

			ListContainer noteLayout = new ListContainer();
			noteLayout.Spacing.Value = padding;
			noteLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
			noteLayout.Alignment.Value = ListContainer.ListAlignment.Min;
			noteLayout.Position.Value = new Vector2(notePadding, notePadding);
			noteLayout.Add(new Binding<Vector2, Point>(noteLayout.Size, x => new Vector2(x.X - notePadding * 2.0f, x.Y - notePadding * 2.0f), noteUi.RenderTargetSize));
			noteUi.Root.Children.Add(noteLayout);

			Sprite noteUiImage = new Sprite();
			noteLayout.Children.Add(noteUiImage);

			TextElement noteUiText = new TextElement();
			noteUiText.FontFile.Value = "Font";
			noteUiText.Tint.Value = new Microsoft.Xna.Framework.Color(0.1f, 0.1f, 0.1f);
			noteUiText.Add(new Binding<float, Vector2>(noteUiText.WrapWidth, x => x.X, noteLayout.Size));
			noteLayout.Children.Add(noteUiText);

			// Toggle note

			Action<bool> showNote = delegate(bool show)
			{
				noteActive.Value = show;
				input.EnableLook.Value = input.EnableMouse.Value = !noteActive;
				main.IsMouseVisible.Value = false;
				enableWalking.Value = enableMoves.Value = !noteActive;
				noteModel.Enabled.Value = noteActive;
				noteUi.Enabled.Value = noteActive;

				model.Stop("Phone", "Note");
				Entity noteEntity = note.Value.Target;
				if (noteEntity != null && noteEntity.Active)
				{
					if (noteActive)
					{
						noteUiImage.Image.Value = noteEntity.GetOrMakeProperty<string>("Image");
						noteUiText.Text.Value = noteEntity.GetOrMakeProperty<string>("Text");
						model.StartClip("Note", 6, true, AnimatedModel.DefaultBlendTime * 2.0f);
						float startRotationY = input.Mouse.Value.Y;
						// Level the player's view
						result.Add(new Animation
						(
							new Animation.Ease
							(
								new Animation.Custom(delegate(float x)
								{
									input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
								}, 0.5f),
								Animation.Ease.Type.OutQuadratic
							)
						));
					}
					else
					{
						Property<bool> collected = noteEntity.GetOrMakeProperty<bool>("Collected");
						if (!collected)
							collected.Value = true;
					}
				}
			};

			// Toggle phone

			Container phoneTutorialMessage = null;

			Action<bool> showPhone = delegate(bool show)
			{
				if (togglePhoneMessage != null)
				{
					((GameMain)main).Menu.HideMessage(result, togglePhoneMessage);
					togglePhoneMessage = null;
				}

				if (phoneTutorialMessage != null)
				{
					((GameMain)main).Menu.HideMessage(result, phoneTutorialMessage);
					phoneTutorialMessage = null;
				}

				if (show || (phone.Schedules.Count == 0 && !phone.WaitForAnswer))
				{
					phoneActive.Value = show;
					input.EnableLook.Value = input.EnableMouse.Value = !phoneActive;
					main.IsMouseVisible.Value = phoneActive;
					enableWalking.Value = enableMoves.Value = !phoneActive;
					phoneModel.Enabled.Value = phoneActive;
					screen.Enabled.Value = phoneActive;
					phoneUi.Enabled.Value = phoneActive;
					phoneLight.Enabled.Value = phoneActive;
					answerContainer.Visible.Value = false;

					model.Stop("Phone", "Note");
					if (phoneActive)
					{
						if (!phone.TutorialShown)
						{
							phone.TutorialShown.Value = true;
							phoneTutorialMessage = ((GameMain)main).Menu.ShowMessage(result, "\\scroll for more");
						}
						phoneScroll.CheckLayout();
						scrollToBottom();

						model.StartClip("Phone", 6, true, AnimatedModel.DefaultBlendTime * 2.0f);

						// Level the player's view
						float startRotationY = input.Mouse.Value.Y;
						result.Add(new Animation
						(
							new Animation.Ease
							(
								new Animation.Custom(delegate(float x)
								{
									input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
								}, 0.5f),
								Animation.Ease.Type.OutQuadratic
							)
						));
					}
				}
			};

			input.Bind(((GameMain)main).Settings.TogglePhone, PCInput.InputState.Up, delegate()
			{
				if (noteActive || phoneActive || phone.CanReceiveMessages)
				{
					if (!phoneActive && (noteActive || note.Value.Target != null && note.Value.Target.Active))
						showNote(!noteActive);
					else if (phone.Enabled)
						showPhone(!phoneActive);
				}
			});

			// Gamepad code for the phone

			input.Add(new CommandBinding(input.GetButtonUp(Buttons.A), () => phoneActive && composeButton.Visible, delegate()
			{
				if (answerContainer.Visible)
					answerList.Children[selectedAnswer].MouseLeftUp.Execute(new Point());
				else
					answerContainer.Visible.Value = true;
			}));

			input.Add(new CommandBinding(input.GetButtonUp(Buttons.B), () => phoneActive && answerContainer.Visible, delegate()
			{
				answerContainer.Visible.Value = false;
			}));

			Action<int> scrollPhone = delegate(int delta)
			{
				if (answerContainer.Visible)
				{
					answerList.Children[selectedAnswer].Highlighted.Value = false;
					selectedAnswer += delta;
					while (selectedAnswer < 0)
						selectedAnswer += answerList.Children.Count;
					while (selectedAnswer > answerList.Children.Count - 1)
						selectedAnswer -= answerList.Children.Count;
					answerList.Children[selectedAnswer].Highlighted.Value = true;
				}
				else
					phoneScroll.MouseScrolled.Execute(new Point(), delta * -4);
			};

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickUp), () => phoneActive, delegate()
			{
				scrollPhone(-1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadUp), () => phoneActive, delegate()
			{
				scrollPhone(-1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickDown), () => phoneActive, delegate()
			{
				scrollPhone(1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadDown), () => phoneActive, delegate()
			{
				scrollPhone(1);
			}));

			msgList.Add(new ListBinding<UIComponent, Phone.Message>
			(
				msgList.Children,
				phone.Messages,
				delegate(Phone.Message msg)
				{
					return makeAlign(makeButton(msg.Incoming ? incomingColor : outgoingColor, "\\" + (msg.Text == null ? msg.ID : msg.Text), messageWidth - padding * 2.0f), !msg.Incoming);
				}
			));

			answerList.Add(new ListBinding<UIComponent, Phone.Ans>
			(
				answerList.Children,
				phone.ActiveAnswers,
				delegate(Phone.Ans answer)
				{
					UIComponent button = makeButton(outgoingColor, "\\" + (answer.Text == null ? answer.ID : answer.Text), messageWidth - padding * 4.0f);
					button.Add(new CommandBinding<Point>(button.MouseLeftUp, delegate(Point p)
					{
						phone.Answer(answer);
						
						// Disable the signal tower
						Entity s = signalTower.Value.Target;
						if (s != null && s.Active)
							s.Get<SignalTower>().Initial.Value = null;

						scrollToBottom();
						if (togglePhoneMessage == null && phone.Schedules.Count == 0) // No more messages incoming
							togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]");
					}));
					return button;
				}
			));

			Action refreshComposeButtonVisibility = delegate()
			{
				bool show = phone.ActiveAnswers.Count > 0 && phone.Schedules.Count == 0;
				answerContainer.Visible.Value &= show;
				composeButton.Visible.Value = show;
				selectedAnswer = 0;
			};
			composeButton.Add(new ListNotifyBinding<Phone.Ans>(refreshComposeButtonVisibility, phone.ActiveAnswers));
			composeButton.Add(new ListNotifyBinding<Phone.Schedule>(refreshComposeButtonVisibility, phone.Schedules));
			refreshComposeButtonVisibility();

			result.Add(new CommandBinding(phone.MessageReceived, delegate()
			{
				if (phoneActive)
					scrollToBottom();
				else
					showPhone(true);
				
				// Animate the new message
				Container lastMessage = (Container)msgList.Children[msgList.Children.Count - 1].Children[0];
				lastMessage.CheckLayout();
				Vector2 originalSize = lastMessage.Size;
				lastMessage.Size.Value = new Vector2(0, originalSize.Y);
				main.AddComponent(new Animation
				(
					new Animation.Ease(new Animation.Vector2MoveTo(lastMessage.Size, originalSize, 0.5f), Animation.Ease.Type.OutExponential)
				));

				AkSoundEngine.PostEvent("Phone_Play", result);
				if (togglePhoneMessage == null && phone.Schedules.Count == 0 && phone.ActiveAnswers.Count == 0) // No more messages incoming, and no more answers to give
					togglePhoneMessage = ((GameMain)main).Menu.ShowMessage(result, "[{{TogglePhone}}]");
			}));

			if (noteActive)
				showNote(true);
			else if (phoneActive)
				showPhone(true);
		}
Example #4
0
        public static void Attach(Main main, Entity entity, Player player, AnimatedModel model, FPSInput input, Phone phone, Property <bool> enableWalking, Property <bool> phoneActive, Property <bool> noteActive)
        {
            UIRenderer phoneUi = entity.GetOrCreate <UIRenderer>("PhoneUI");

            model["Phone"].Speed = model["VRPhone"].Speed = model["Note"].Speed = model["VRNote"].Speed = 0.25f;

            const float phoneWidth = 200.0f;

            phoneUi.RenderTargetBackground.Value = Microsoft.Xna.Framework.Color.White;
            phoneUi.RenderTargetSize.Value       = new Point((int)phoneWidth, (int)(phoneWidth * 2.0f));
            phoneUi.Serialize     = false;
            phoneUi.Enabled.Value = false;
#if VR
            if (main.VR)
            {
                phoneUi.Reticle.Tint.Value = new Color(0.0f, 0.0f, 0.0f);
            }
#endif

            Model phoneModel = entity.GetOrCreate <Model>("PhoneModel");
            phoneModel.Filename.Value = "Models\\phone";
            phoneModel.Color.Value    = new Vector3(0.13f, 0.13f, 0.13f);
            phoneModel.Serialize      = false;
            phoneModel.Enabled.Value  = false;

            Property <Matrix> phoneBone = model.GetBoneTransform("Phone");
            phoneModel.Add(new Binding <Matrix>(phoneModel.Transform, () => phoneBone.Value * model.Transform, phoneBone, model.Transform));

            Model screen = entity.GetOrCreate <Model>("Screen");
            screen.Filename.Value = "Models\\plane";
            screen.Add(new Binding <Microsoft.Xna.Framework.Graphics.RenderTarget2D>(screen.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), phoneUi.RenderTarget));
            screen.Add(new Binding <Matrix>(screen.Transform, x => Matrix.CreateTranslation(0.015f, 0.0f, 0.0f) * x, phoneModel.Transform));
            screen.Serialize     = false;
            screen.Enabled.Value = false;

            PointLight phoneLight = entity.Create <PointLight>();
            phoneLight.Serialize         = false;
            phoneLight.Enabled.Value     = false;
            phoneLight.Attenuation.Value = 0.5f;
            phoneLight.Add(new Binding <Vector3, Matrix>(phoneLight.Position, x => x.Translation, screen.Transform));

            PointLight noteLight = entity.Create <PointLight>();
            noteLight.Serialize         = false;
            noteLight.Enabled.Value     = false;
            noteLight.Attenuation.Value = 1.0f;
            noteLight.Color.Value       = new Vector3(0.3f);
            noteLight.Add(new Binding <Vector3>(noteLight.Position, () => Vector3.Transform(new Vector3(0.25f, 0.0f, 0.0f), phoneBone.Value * model.Transform), phoneBone, model.Transform));

            const float screenScale = 0.0007f;
            screen.Scale.Value = new Vector3(1.0f, (float)phoneUi.RenderTargetSize.Value.Y * screenScale, (float)phoneUi.RenderTargetSize.Value.X * screenScale);

            // Transform screen space mouse position into 3D, then back into the 2D space of the phone UI
            Property <Matrix> screenTransform = new Property <Matrix>();
            screen.Add(new Binding <Matrix>(screenTransform, () => Matrix.CreateScale(screen.Scale) * screen.Transform, screen.Scale, screen.Transform));
            phoneUi.Setup3D(screenTransform);

            // Phone UI

            const float padding      = 8.0f;
            const float messageWidth = phoneWidth - padding * 2.0f;

            Func <Property <Color>, string, float, Container> makeButton = delegate(Property <Color> color, string text, float width)
            {
                Container bg = new Container();
                bg.Tint.Value          = color;
                bg.PaddingBottom.Value = bg.PaddingLeft.Value = bg.PaddingRight.Value = bg.PaddingTop.Value = padding * 0.5f;
                bg.Add(new Binding <Color>(bg.Tint, () => bg.Highlighted ? new Color(color.Value.ToVector4() + new Vector4(0.2f, 0.2f, 0.2f, 0.0f)) : color, bg.Highlighted, color));

                TextElement msg = new TextElement();
                msg.Name.Value      = "Text";
                msg.FontFile.Value  = main.Font;
                msg.Text.Value      = text;
                msg.WrapWidth.Value = width;
                bg.Children.Add(msg);
                return(bg);
            };

            Action <Container, float> centerButton = delegate(Container button, float width)
            {
                TextElement text = (TextElement)button.Children[0];
                text.AnchorPoint.Value = new Vector2(0.5f, 0);
                text.Add(new Binding <Vector2>(text.Position, x => new Vector2(x.X * 0.5f, padding), button.Size));
                button.ResizeHorizontal.Value = false;
                button.ResizeVertical.Value   = false;
                button.Size.Value             = new Vector2(width, 36.0f * main.FontMultiplier);
            };

            Func <UIComponent, bool, Container> makeAlign = delegate(UIComponent component, bool right)
            {
                Container container = new Container();
                container.Opacity.Value          = 0.0f;
                container.PaddingBottom.Value    = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 0.0f;
                container.ResizeHorizontal.Value = false;
                container.Size.Value             = new Vector2(messageWidth, 0.0f);
                component.AnchorPoint.Value      = new Vector2(right ? 1.0f : 0.0f, 0.0f);
                component.Position.Value         = new Vector2(right ? messageWidth : 0.0f, 0.0f);
                container.Children.Add(component);
                return(container);
            };

            Property <Color> incomingColor = new Property <Color> {
                Value = new Color(0.0f, 0.0f, 0.0f, 1.0f)
            };
            Property <Color> outgoingColor = new Property <Color> {
                Value = new Color(0.0f, 0.175f, 0.35f, 1.0f)
            };
            Property <Color> alternateSenderColor = new Property <Color> {
                Value = new Color(0.25f, 0.0f, 0.25f, 1.0f)
            };
            Property <Color> composeColor = new Property <Color> {
                Value = new Color(0.5f, 0.0f, 0.0f, 1.0f)
            };
            Property <Color> disabledColor = new Property <Color> {
                Value = new Color(0.35f, 0.35f, 0.35f, 1.0f)
            };
            Property <Color> topBarColor = new Property <Color> {
                Value = new Color(0.15f, 0.15f, 0.15f, 1.0f)
            };

            Container topBarContainer = new Container();
            topBarContainer.ResizeHorizontal.Value = false;
            topBarContainer.Size.Value             = new Vector2(phoneUi.RenderTargetSize.Value.X, 0.0f);
            topBarContainer.Tint.Value             = topBarColor;
            phoneUi.Root.Children.Add(topBarContainer);

            ListContainer phoneTopBar = new ListContainer();
            phoneTopBar.Orientation.Value = ListContainer.ListOrientation.Horizontal;
            phoneTopBar.Spacing.Value     = padding;
            topBarContainer.Children.Add(phoneTopBar);

            Sprite signalIcon = new Sprite();
            signalIcon.Image.Value = "Images\\signal";
            phoneTopBar.Children.Add(signalIcon);

            TextElement noService = new TextElement();
            noService.FontFile.Value = main.Font;
            noService.Text.Value     = "\\no service";
            phoneTopBar.Children.Add(noService);

            signalIcon.Add(new Binding <bool>(signalIcon.Visible, () => player.SignalTower.Value.Target != null || phone.ActiveAnswers.Length > 0 || phone.Schedules.Length > 0, player.SignalTower, phone.ActiveAnswers.Length, phone.Schedules.Length));
            noService.Add(new Binding <bool>(noService.Visible, x => !x, signalIcon.Visible));

            ListContainer tabs = new ListContainer();
            tabs.Orientation.Value = ListContainer.ListOrientation.Horizontal;
            tabs.Spacing.Value     = 0;
            phoneUi.Root.Children.Add(tabs);

            Property <Color> messageTabColor = new Property <Color> {
                Value = outgoingColor
            };
            phoneUi.Add(new Binding <Color, Phone.Mode>(messageTabColor, x => x == Phone.Mode.Messages ? outgoingColor : topBarColor, phone.CurrentMode));
            Container messageTab = makeButton(messageTabColor, "\\messages", phoneUi.RenderTargetSize.Value.X * 0.5f - padding);
            centerButton(messageTab, phoneUi.RenderTargetSize.Value.X * 0.5f);
            tabs.Children.Add(messageTab);
            messageTab.Add(new CommandBinding(messageTab.MouseLeftUp, delegate()
            {
                phone.CurrentMode.Value = Phone.Mode.Messages;
            }));

            Property <Color> photoTabColor = new Property <Color> {
                Value = topBarColor
            };
            phoneUi.Add(new Binding <Color>(photoTabColor, delegate()
            {
                if (phone.CurrentMode == Phone.Mode.Photos)
                {
                    return(outgoingColor);
                }
                else if (string.IsNullOrEmpty(phone.Photo))
                {
                    return(disabledColor);
                }
                else
                {
                    return(topBarColor);
                }
            }, phone.CurrentMode, phone.Photo));
            Container photoTab = makeButton(photoTabColor, "\\photos", phoneUi.RenderTargetSize.Value.X * 0.5f - padding);
            centerButton(photoTab, phoneUi.RenderTargetSize.Value.X * 0.5f);
            tabs.Children.Add(photoTab);
            photoTab.Add(new CommandBinding(photoTab.MouseLeftUp, delegate()
            {
                if (!string.IsNullOrEmpty(phone.Photo))
                {
                    phone.CurrentMode.Value = Phone.Mode.Photos;
                }
            }));

            tabs.Add(new Binding <Vector2>(tabs.Position, x => new Vector2(0, x.Y), topBarContainer.Size));

            ListContainer messageLayout = new ListContainer();
            messageLayout.Spacing.Value     = padding;
            messageLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
            messageLayout.Add(new Binding <Vector2>(messageLayout.Position, () => new Vector2(padding, topBarContainer.Size.Value.Y + tabs.Size.Value.Y), topBarContainer.Size, tabs.Size));
            messageLayout.Add(new Binding <Vector2>(messageLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X - padding * 2.0f, phoneUi.RenderTargetSize.Value.Y - padding - topBarContainer.Size.Value.Y - tabs.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size, tabs.Size));
            messageLayout.Add(new Binding <bool, Phone.Mode>(messageLayout.Visible, x => x == Phone.Mode.Messages, phone.CurrentMode));
            phoneUi.Root.Children.Add(messageLayout);

            Container photoLayout = new Container();
            photoLayout.Opacity.Value     = 0;
            photoLayout.PaddingLeft.Value = photoLayout.PaddingRight.Value = photoLayout.PaddingTop.Value = photoLayout.PaddingBottom.Value = 0;
            photoLayout.Add(new Binding <Vector2>(photoLayout.Position, () => new Vector2(0, topBarContainer.Size.Value.Y + tabs.Size.Value.Y), topBarContainer.Size, tabs.Size));
            photoLayout.Add(new Binding <Vector2>(photoLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X, phoneUi.RenderTargetSize.Value.Y - topBarContainer.Size.Value.Y - tabs.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size, tabs.Size));
            photoLayout.Add(new Binding <bool>(photoLayout.Visible, x => !x, messageLayout.Visible));
            phoneUi.Root.Children.Add(photoLayout);

            Sprite photoImage = new Sprite();
            photoImage.AnchorPoint.Value = new Vector2(0.5f, 0.5f);
            photoImage.Add(new Binding <string>(photoImage.Image, phone.Photo));
            photoImage.Add(new Binding <Vector2>(photoImage.Position, x => x * 0.5f, photoLayout.Size));
            photoLayout.Children.Add(photoImage);

            Container   composeButton = makeButton(composeColor, "\\compose", messageWidth - padding * 2.0f);
            TextElement composeText   = (TextElement)composeButton.GetChildByName("Text");
            composeText.Add(new Binding <string, bool>(composeText.Text, x => x ? "\\compose gamepad" : "\\compose", main.GamePadConnected));
            UIComponent composeAlign = makeAlign(composeButton, true);

            Scroller phoneScroll = new Scroller();
            phoneScroll.ResizeVertical.Value = false;
            phoneScroll.Add(new Binding <Vector2>(phoneScroll.Size, () => new Vector2(messageLayout.Size.Value.X, messageLayout.Size.Value.Y - messageLayout.Spacing.Value - composeAlign.ScaledSize.Value.Y), messageLayout.Size, messageLayout.Spacing, composeAlign.ScaledSize));

            messageLayout.Children.Add(phoneScroll);
            messageLayout.Children.Add(composeAlign);

            ListContainer msgList = new ListContainer();
            msgList.Spacing.Value             = padding * 0.5f;
            msgList.Orientation.Value         = ListContainer.ListOrientation.Vertical;
            msgList.ResizePerpendicular.Value = false;
            msgList.Size.Value = new Vector2(messageWidth, 0.0f);
            phoneScroll.Children.Add(msgList);

            Container answerContainer = new Container();
            answerContainer.PaddingBottom.Value = answerContainer.PaddingLeft.Value = answerContainer.PaddingRight.Value = answerContainer.PaddingTop.Value = padding;
            answerContainer.Tint.Value          = incomingColor;
            answerContainer.AnchorPoint.Value   = new Vector2(1.0f, 1.0f);
            answerContainer.Add(new Binding <Vector2>(answerContainer.Position, () => composeAlign.GetAbsolutePosition() + new Vector2(composeAlign.ScaledSize.Value.X, 0), composeAlign.Position, composeAlign.ScaledSize));
            phoneUi.Root.Children.Add(answerContainer);
            answerContainer.Visible.Value = false;

            ListContainer answerList = new ListContainer();
            answerList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            answerList.Alignment.Value   = ListContainer.ListAlignment.Max;
            answerContainer.Children.Add(answerList);

            int selectedAnswer = 0;

            composeButton.Add(new CommandBinding(composeButton.MouseLeftUp, delegate()
            {
                answerContainer.Visible.Value = !answerContainer.Visible;
                if (answerContainer.Visible && main.GamePadConnected)
                {
                    selectedAnswer = 0;
                    foreach (UIComponent answer in answerList.Children)
                    {
                        answer.Highlighted.Value = false;
                    }
                    answerList.Children[0].Highlighted.Value = true;
                }
            }));

            tabs.Add(new Binding <bool>(tabs.EnableInput, () => !main.Paused && !answerContainer.Visible, answerContainer.Visible, main.Paused));
            msgList.Add(new Binding <bool>(msgList.EnableInput, () => !main.Paused && !answerContainer.Visible, answerContainer.Visible, main.Paused));
            answerContainer.Add(new Binding <bool>(answerContainer.EnableInput, x => !x, main.Paused));
            composeButton.Add(new Binding <bool>(composeButton.EnableInput, x => !x, main.Paused));

            Action scrollToBottom = delegate()
            {
                // HACK
                Animation scroll = new Animation
                                   (
                    new Animation.Delay(0.01f),
                    new Animation.Execute(delegate()
                {
                    phoneScroll.ScrollToBottom();
                })
                                   );
                entity.Add(scroll);
            };

            // Note

            UIRenderer noteUi = entity.GetOrCreate <UIRenderer>("NoteUI");

            const float noteWidth = 400.0f;

            noteUi.RenderTargetBackground.Value = new Microsoft.Xna.Framework.Color(0.8f, 0.75f, 0.7f);
            noteUi.RenderTargetSize.Value       = new Point((int)noteWidth, (int)(noteWidth * 1.29f));       // 8.5x11 aspect ratio
            noteUi.Serialize     = false;
            noteUi.Enabled.Value = false;

            Model noteModel = entity.GetOrCreate <Model>("Note");
            noteModel.Filename.Value = "Models\\note";
            noteModel.Add(new Binding <Microsoft.Xna.Framework.Graphics.RenderTarget2D>(noteModel.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), noteUi.RenderTarget));
            noteModel.Add(new Binding <Matrix>(noteModel.Transform, x => Matrix.CreateTranslation(-0.005f, 0.05f, 0.08f) * x, phoneModel.Transform));
            noteModel.Serialize     = false;
            noteModel.Enabled.Value = false;

            Container togglePhoneMessage = null;

            entity.Add(new NotifyBinding(delegate()
            {
                bool hasSignalTower = (player.SignalTower.Value.Target != null && player.SignalTower.Value.Target.Active && !string.IsNullOrEmpty(player.SignalTower.Value.Target.Get <SignalTower>().Initial));
                if (hasSignalTower)
                {
                    phone.Enabled.Value = true;
                }

                bool hasNoteOrSignalTower = (player.Note.Value.Target != null && player.Note.Value.Target.Active) || hasSignalTower;

                if (togglePhoneMessage == null && hasNoteOrSignalTower)
                {
                    togglePhoneMessage = main.Menu.ShowMessage(entity, hasSignalTower ? "\\signal tower prompt" : "\\note prompt");
                }
                else if (togglePhoneMessage != null && !hasNoteOrSignalTower && !phoneActive && !noteActive)
                {
                    main.Menu.HideMessage(entity, togglePhoneMessage);
                    togglePhoneMessage = null;
                }
            }, player.Note, player.SignalTower));

            entity.Add(new CommandBinding(entity.Delete, delegate()
            {
                main.Menu.HideMessage(null, togglePhoneMessage);
            }));

            // Note UI

            const float notePadding = 40.0f;

            ListContainer noteLayout = new ListContainer();
            noteLayout.Spacing.Value     = padding;
            noteLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
            noteLayout.Alignment.Value   = ListContainer.ListAlignment.Min;
            noteLayout.Position.Value    = new Vector2(notePadding, notePadding);
            noteLayout.Add(new Binding <Vector2, Point>(noteLayout.Size, x => new Vector2(x.X - notePadding * 2.0f, x.Y - notePadding * 2.0f), noteUi.RenderTargetSize));
            noteUi.Root.Children.Add(noteLayout);

            Sprite noteUiImage = new Sprite();
            noteLayout.Children.Add(noteUiImage);

            TextElement noteUiText = new TextElement();
            noteUiText.FontFile.Value = main.Font;
            noteUiText.Tint.Value     = new Microsoft.Xna.Framework.Color(0.1f, 0.1f, 0.1f);
            noteUiText.Add(new Binding <float, Vector2>(noteUiText.WrapWidth, x => x.X, noteLayout.Size));
            noteLayout.Children.Add(noteUiText);

            // Toggle note
            Animation noteAnim = null;

            float         startRotationY = 0;
            Action <bool> showNote       = delegate(bool show)
            {
                model.Stop("Phone", "Note", "VRPhone", "VRNote");
                Entity noteEntity = player.Note.Value.Target;
                noteActive.Value = show && noteEntity != null;
                Note note = noteEntity != null?noteEntity.Get <Note>() : null;

                if (noteActive)
                {
                    input.EnableLook.Value  = input.EnableMouse.Value = false;
                    enableWalking.Value     = false;
                    noteModel.Enabled.Value = true;
                    noteUi.Enabled.Value    = true;
                    noteLight.Enabled.Value = true;
                    Session.Recorder.Event(main, "Note", note.Text);
                    noteUiImage.Image.Value = note.Image;
                    noteUiText.Text.Value   = note.Text;
                    string noteAnimation;
#if VR
                    if (main.VR)
                    {
                        noteAnimation = "VRNote";
                    }
                    else
#endif
                    noteAnimation = "Note";

                    model.StartClip(noteAnimation, 6, true, AnimatedModel.DefaultBlendTime * 2.0f);
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_NOTE_PICKUP, entity);

                    if (noteAnim != null && noteAnim.Active)
                    {
                        noteAnim.Delete.Execute();
                    }
                    else
                    {
                        startRotationY = input.Mouse.Value.Y;
                    }
                    // Level the player's view
                    noteAnim = new Animation
                               (
                        new Animation.Ease
                        (
                            new Animation.Custom(delegate(float x)
                    {
                        input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
                    }, 0.5f),
                            Animation.Ease.EaseType.OutQuadratic
                        )
                               );
                    entity.Add(noteAnim);
                }
                else
                {
                    enableWalking.Value = true;
                    if (note != null)
                    {
                        Session.Recorder.Event(main, "NoteEnd");
                    }
                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_NOTE_DROP, entity);
                    if (note != null && !note.IsCollected)
                    {
                        note.IsCollected.Value = true;
                    }

                    // Return the player's view
                    if (noteAnim != null && noteAnim.Active)
                    {
                        noteAnim.Delete.Execute();
                    }
                    noteAnim = new Animation
                               (
                        new Animation.Ease
                        (
                            new Animation.Custom(delegate(float x)
                    {
                        input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * x);
                    }, 0.5f),
                            Animation.Ease.EaseType.OutQuadratic
                        ),
                        new Animation.Execute(delegate()
                    {
                        noteModel.Enabled.Value = false;
                        noteUi.Enabled.Value    = false;
                        noteLight.Enabled.Value = false;
                        input.EnableLook.Value  = input.EnableMouse.Value = true;
                    })
                               );
                    entity.Add(noteAnim);
                }
            };

            // Toggle phone

            Animation phoneAnim = null;

            Action <bool> showPhone = delegate(bool show)
            {
                if (togglePhoneMessage != null)
                {
                    main.Menu.HideMessage(entity, togglePhoneMessage);
                    togglePhoneMessage = null;
                }

                if (show || (phone.Schedules.Length == 0 && !phone.WaitForAnswer))
                {
                    phoneActive.Value             = show;
                    answerContainer.Visible.Value = false;

                    model.Stop("Phone", "Note", "VRPhone", "VRNote");
                    if (phoneActive)
                    {
                        phoneUi.IsMouseVisible.Value = true;
                        enableWalking.Value          = false;
                        phoneModel.Enabled.Value     = true;
                        screen.Enabled.Value         = true;
                        phoneUi.Enabled.Value        = true;
                        phoneLight.Enabled.Value     = true;
                        input.EnableLook.Value       = input.EnableMouse.Value = false;
                        Session.Recorder.Event(main, "Phone");
                        phoneScroll.CheckLayout();
                        scrollToBottom();

                        string phoneAnimation;
#if VR
                        if (main.VR)
                        {
                            phoneAnimation = "VRPhone";
                        }
                        else
#endif
                        phoneAnimation = "Phone";

                        model.StartClip(phoneAnimation, 6, true, AnimatedModel.DefaultBlendTime * 2.0f);

                        // Level the player's view
                        if (phoneAnim != null && phoneAnim.Active)
                        {
                            phoneAnim.Delete.Execute();
                        }
                        else
                        {
                            startRotationY = input.Mouse.Value.Y;
                        }
                        phoneAnim = new Animation
                                    (
                            new Animation.Ease
                            (
                                new Animation.Custom(delegate(float x)
                        {
                            input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
                        }, 0.5f),
                                Animation.Ease.EaseType.OutQuadratic
                            )
                                    );
                        entity.Add(phoneAnim);
                    }
                    else
                    {
                        Session.Recorder.Event(main, "PhoneEnd");
                        enableWalking.Value          = true;
                        phoneUi.IsMouseVisible.Value = false;

                        // Return the player's view
                        if (phoneAnim != null && phoneAnim.Active)
                        {
                            phoneAnim.Delete.Execute();
                        }
                        phoneAnim = new Animation
                                    (
                            new Animation.Ease
                            (
                                new Animation.Custom(delegate(float x)
                        {
                            input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * x);
                        }, 0.5f),
                                Animation.Ease.EaseType.OutQuadratic
                            ),
                            new Animation.Execute(delegate()
                        {
                            phoneModel.Enabled.Value = false;
                            screen.Enabled.Value     = false;
                            phoneUi.Enabled.Value    = false;
                            phoneLight.Enabled.Value = false;
                            input.EnableLook.Value   = input.EnableMouse.Value = true;
                        })
                                    );
                        entity.Add(phoneAnim);
                    }
                }
            };

            input.Bind(main.Settings.TogglePhone, PCInput.InputState.Down, delegate()
            {
                // Special hack to prevent phone toggling when you're trying to open the Steam overlay
                if (main.Settings.TogglePhone.Value.Key == Keys.Tab && input.GetKey(Keys.LeftShift))
                {
                    return;
                }

                if (noteActive || phoneActive || phone.CanReceiveMessages)
                {
                    if (!phoneActive && (noteActive || player.Note.Value.Target != null))
                    {
                        showNote(!noteActive);
                    }
                    else if (phone.Enabled)
                    {
                        showPhone(!phoneActive);
                    }
                }
            });

            phone.Add(new CommandBinding(phone.Show, delegate()
            {
                phone.Enabled.Value = true;
                if (!phoneActive)
                {
                    showPhone(true);
                }
            }));

            // Gamepad code for the phone

            input.Add(new CommandBinding(input.GetButtonUp(Buttons.A), () => phoneActive && composeButton.Visible && phone.CurrentMode.Value == Phone.Mode.Messages, delegate()
            {
                if (answerContainer.Visible)
                {
                    answerList.Children[selectedAnswer].MouseLeftUp.Execute();
                }
                else
                {
                    composeButton.MouseLeftUp.Execute();
                }
            }));

            input.Add(new CommandBinding(input.GetButtonUp(Buttons.B), () => phoneActive && answerContainer.Visible, delegate()
            {
                answerContainer.Visible.Value = false;
            }));

            const float  moveInterval   = 0.1f;
            const float  switchInterval = 0.2f;
            float        lastScroll     = 0;
            float        lastModeSwitch = 0;
            Action <int> scrollPhone    = delegate(int delta)
            {
                if (main.TotalTime - lastScroll > moveInterval &&
                    main.TotalTime - lastModeSwitch > switchInterval)
                {
                    if (answerContainer.Visible)
                    {
                        answerList.Children[selectedAnswer].Highlighted.Value = false;
                        selectedAnswer += delta;
                        while (selectedAnswer < 0)
                        {
                            selectedAnswer += answerList.Children.Length;
                        }
                        while (selectedAnswer > answerList.Children.Length - 1)
                        {
                            selectedAnswer -= answerList.Children.Length;
                        }
                        answerList.Children[selectedAnswer].Highlighted.Value = true;
                    }
                    else
                    {
                        phoneScroll.MouseScrolled.Execute(delta * -4);
                    }
                    lastScroll = main.TotalTime;
                }
            };

            Action switchMode = delegate()
            {
                if (main.TotalTime - lastScroll > switchInterval &&
                    main.TotalTime - lastModeSwitch > moveInterval)
                {
                    Phone.Mode current  = phone.CurrentMode;
                    Phone.Mode nextMode = current == Phone.Mode.Messages ? Phone.Mode.Photos : Phone.Mode.Messages;
                    if (nextMode == Phone.Mode.Photos && string.IsNullOrEmpty(phone.Photo))
                    {
                        nextMode = Phone.Mode.Messages;
                    }
                    phone.CurrentMode.Value = nextMode;
                    lastModeSwitch          = main.TotalTime;
                }
            };
            input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickLeft), () => phoneActive && !answerContainer.Visible, switchMode));
            input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickRight), () => phoneActive && !answerContainer.Visible, switchMode));
            input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadLeft), () => phoneActive && !answerContainer.Visible, switchMode));
            input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadRight), () => phoneActive && !answerContainer.Visible, switchMode));

            input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickUp), () => phoneActive, delegate()
            {
                scrollPhone(-1);
            }));

            input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadUp), () => phoneActive, delegate()
            {
                scrollPhone(-1);
            }));

            input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickDown), () => phoneActive, delegate()
            {
                scrollPhone(1);
            }));

            input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadDown), () => phoneActive, delegate()
            {
                scrollPhone(1);
            }));

            Func <Phone.Sender, Property <Color> > messageColor = delegate(Phone.Sender sender)
            {
                switch (sender)
                {
                case Phone.Sender.Player:
                    return(outgoingColor);

                case Phone.Sender.A:
                    return(incomingColor);

                default:
                    return(alternateSenderColor);
                }
            };

            msgList.Add(new ListBinding <UIComponent, Phone.Message>
                        (
                            msgList.Children,
                            phone.Messages,
                            delegate(Phone.Message msg)
            {
                return(makeAlign(makeButton(messageColor(msg.Sender), "\\" + msg.Name, messageWidth - padding * 2.0f), msg.Sender == Phone.Sender.Player));
            }
                        ));

            Action <float, Container> animateMessage = delegate(float delay, Container msg)
            {
                msg.CheckLayout();
                Vector2 originalSize = msg.Size;
                msg.Size.Value = new Vector2(0, originalSize.Y);
                entity.Add(new Animation
                           (
                               new Animation.Delay(delay),
                               new Animation.Ease(new Animation.Vector2MoveTo(msg.Size, originalSize, 0.5f), Animation.Ease.EaseType.OutExponential)
                           ));
            };

            Container typingIndicator = null;

            Action showTypingIndicator = delegate()
            {
                typingIndicator = makeAlign(makeButton(incomingColor, "\\...", messageWidth - padding * 2.0f), false);
                msgList.Children.Add(typingIndicator);
                animateMessage(0.2f, typingIndicator);
            };

            if (phone.Schedules.Length > 0)
            {
                showTypingIndicator();
            }

            answerList.Add(new ListBinding <UIComponent, Phone.Ans>
                           (
                               answerList.Children,
                               phone.ActiveAnswers,
                               delegate(Phone.Ans answer)
            {
                UIComponent button = makeButton(outgoingColor, "\\" + answer.Name, messageWidth - padding * 4.0f);
                button.Add(new CommandBinding(button.MouseLeftUp, delegate()
                {
                    if (!phone.WaitForAnswer)                             // If we're not waiting for an answer, the player must be initiating a conversation
                    {
                        // This is the start of a conversation
                        // Disable the signal tower if we're in range
                        Entity s = player.SignalTower.Value.Target;
                        if (s != null)
                        {
                            s.Get <SignalTower>().Initial.Value = null;
                        }
                    }

                    AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PHONE_SEND, entity);
                    phone.Answer(answer);

                    scrollToBottom();
                    if (phone.Schedules.Length == 0)                             // No more messages incoming
                    {
                        if (togglePhoneMessage == null)
                        {
                            togglePhoneMessage = main.Menu.ShowMessage(entity, "\\phone done prompt");
                        }
                    }
                    else
                    {
                        // More messages incoming
                        showTypingIndicator();
                    }
                }));
                return(button);
            }
                           ));

            Action refreshComposeButtonVisibility = delegate()
            {
                bool show = phone.ActiveAnswers.Length > 0 && phone.Schedules.Length == 0;
                answerContainer.Visible.Value &= show;
                composeButton.Visible.Value    = show;
                selectedAnswer = 0;
            };
            composeButton.Add(new ListNotifyBinding <Phone.Ans>(refreshComposeButtonVisibility, phone.ActiveAnswers));
            composeButton.Add(new ListNotifyBinding <Phone.Schedule>(refreshComposeButtonVisibility, phone.Schedules));
            refreshComposeButtonVisibility();

            entity.Add(new CommandBinding(phone.MessageReceived, delegate()
            {
                if (typingIndicator != null)
                {
                    typingIndicator.Delete.Execute();
                    typingIndicator = null;
                }

                if (phone.Schedules.Length > 0)
                {
                    showTypingIndicator();
                }

                float delay;
                if (phoneActive)
                {
                    scrollToBottom();
                    delay = 0;
                }
                else
                {
                    showPhone(true);
                    delay = 0.5f;
                }

                // Animate the new message
                animateMessage(delay, (Container)msgList.Children[msgList.Children.Length - 1].Children[0]);

                AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PHONE_VIBRATE, entity);
                if (togglePhoneMessage == null && phone.Schedules.Length == 0 && phone.ActiveAnswers.Length == 0)                 // No more messages incoming, and no more answers to give
                {
                    togglePhoneMessage = main.Menu.ShowMessage(entity, "[{{TogglePhone}}]");
                }
            }));

            if (noteActive)
            {
                showNote(true);
            }
            else if (phoneActive)
            {
                showPhone(true);
            }
        }
Example #5
0
File: Main.cs Project: kleril/Lemma
		public void ScheduleSave()
		{
			if (this.MapFile.Value != Main.MenuMap && (this.scheduledSave == null || !this.scheduledSave.Active))
			{
				bool originalCanPause = this.Menu.CanPause;
				this.Menu.CanPause.Value = false;
				Container saveNotification = new Container();
				TextElement saveNotificationText = new TextElement();
				this.scheduledSave = new Animation
				(
					new Animation.Delay(0.6f),
					new Animation.Execute(delegate()
					{
						Point size;
#if VR
						if (this.VR)
							size = this.VRActualScreenSize;
						else
#endif
							size = this.ScreenSize;
						this.Screenshot.Take(size);
					}),
					new Animation.Delay(0.01f),
					new Animation.Execute(delegate()
					{
						saveNotification.Tint.Value = Microsoft.Xna.Framework.Color.Black;
						saveNotification.Opacity.Value = UIFactory.Opacity;
						saveNotificationText.Name.Value = "Text";
						saveNotificationText.FontFile.Value = this.Font;
						saveNotificationText.Text.Value = "\\saving";
						saveNotification.Children.Add(saveNotificationText);
						this.UI.Root.GetChildByName("Notifications").Children.Add(saveNotification);
					}),
					new Animation.Delay(0.01f),
					new Animation.Execute(delegate()
					{
						this.SaveOverwrite();
					}),
					new Animation.Delay(0.01f),
					new Animation.Set<string>(saveNotificationText.Text, "\\saved"),
					new Animation.Parallel
					(
						new Animation.FloatMoveTo(saveNotification.Opacity, 0.0f, 1.0f),
						new Animation.FloatMoveTo(saveNotificationText.Opacity, 0.0f, 1.0f)
					),
					new Animation.Execute(saveNotification.Delete)
				);
				this.scheduledSave.Add(new CommandBinding(this.scheduledSave.Delete, delegate()
				{
					this.Screenshot.Clear();
					this.UI.Root.GetChildByName("Notifications").Children.Clear();
					this.Menu.CanPause.Value = originalCanPause;
					this.scheduledSave = null;
				}));
				WorldFactory.Instance.Add(this.scheduledSave);
			}
		}
Example #6
0
		protected override void LoadContent()
		{
			if (this.firstLoadContentCall)
			{
				// Initialize Wwise
				AkGlobalSoundEngineInitializer initializer = new AkGlobalSoundEngineInitializer(Path.Combine(this.Content.RootDirectory, "Wwise"));
				this.AddComponent(initializer);

				this.Listener = new AkListener();
				this.Listener.Add(new Binding<Vector3>(this.Listener.Position, this.Camera.Position));
				this.Listener.Add(new Binding<Vector3>(this.Listener.Forward, this.Camera.Forward));
				this.Listener.Add(new Binding<Vector3>(this.Listener.Up, this.Camera.Up));
				this.AddComponent(this.Listener);

				// Create the renderer.
				this.LightingManager = new LightingManager();
				this.AddComponent(this.LightingManager);
				this.Renderer = new Renderer(this, this.ScreenSize, true, true, true, true);

				this.AddComponent(this.Renderer);
				this.renderParameters = new RenderParameters
				{
					Camera = this.Camera,
					IsMainRender = true
				};
				this.firstLoadContentCall = false;

				this.UI = new UIRenderer();
				this.AddComponent(this.UI);

				GeeUI.GeeUI.Initialize(this);

				this.ConsoleUI = new ConsoleUI();
				this.AddComponent(ConsoleUI);

				this.Console = new Console.Console();
				this.AddComponent(Console);

				PCInput input = new PCInput();
				this.AddComponent(input);

#if DEVELOPMENT
				input.Add(new CommandBinding(input.GetChord(new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.S }), delegate()
				{
					// High-resolution screenshot
					Screenshot s = new Screenshot();
					this.AddComponent(s);
					s.Take(new Point(4096, 2304), delegate()
					{
						string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
						string path;
						int i = 0;
						do
						{
							path = Path.Combine(desktop, "lemma-screen" + i.ToString() + ".png");
							i++;
						}
						while (File.Exists(path));

						using (Stream stream = File.OpenWrite(path))
							s.Buffer.SaveAsPng(stream, s.Size.X, s.Size.Y);
						s.Delete.Execute();
					});
				}));
#endif

#if PERFORMANCE_MONITOR
				this.performanceMonitor = new ListContainer();
				this.performanceMonitor.Add(new Binding<Vector2, Point>(performanceMonitor.Position, x => new Vector2(0, x.Y), this.ScreenSize));
				this.performanceMonitor.AnchorPoint.Value = new Vector2(0, 1);
				this.performanceMonitor.Visible.Value = false;
				this.performanceMonitor.Name.Value = "PerformanceMonitor";
				this.UI.Root.Children.Add(this.performanceMonitor);

				Action<string, Property<double>> addTimer = delegate(string label, Property<double> property)
				{
					TextElement text = new TextElement();
					text.FontFile.Value = "Font";
					text.Add(new Binding<string, double>(text.Text, x => label + ": " + (x * 1000.0).ToString("F") + "ms", property));
					this.performanceMonitor.Children.Add(text);
				};

				Action<string, Property<int>> addCounter = delegate(string label, Property<int> property)
				{
					TextElement text = new TextElement();
					text.FontFile.Value = "Font";
					text.Add(new Binding<string, int>(text.Text, x => label + ": " + x.ToString(), property));
					this.performanceMonitor.Children.Add(text);
				};

				TextElement frameRateText = new TextElement();
				frameRateText.FontFile.Value = "Font";
				frameRateText.Add(new Binding<string, float>(frameRateText.Text, x => "FPS: " + x.ToString("0"), this.frameRate));
				this.performanceMonitor.Children.Add(frameRateText);

				addTimer("Physics", this.physicsTime);
				addTimer("Update", this.updateTime);
				addTimer("Pre-frame", this.preframeTime);
				addTimer("Raw render", this.rawRenderTime);
				addTimer("Shadow render", this.shadowRenderTime);
				addTimer("Post-process", this.postProcessTime);
				addTimer("Non-post-processed", this.unPostProcessedTime);
				addCounter("Draw calls", this.drawCalls);
				addCounter("Triangles", this.triangles);

				input.Add(new CommandBinding(input.GetChord(new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.P }), delegate()
				{
					this.performanceMonitor.Visible.Value = !this.performanceMonitor.Visible;
				}));
#endif

				try
				{
					IEnumerable<string> globalStaticScripts = Directory.GetFiles(Path.Combine(this.Content.RootDirectory, "GlobalStaticScripts"), "*", SearchOption.AllDirectories).Select(x => Path.Combine("..\\GlobalStaticScripts", Path.GetFileNameWithoutExtension(x)));
					foreach (string scriptName in globalStaticScripts)
						this.executeStaticScript(scriptName);
				}
				catch (IOException)
				{

				}
			}
			else
			{
				foreach (IDrawableComponent c in this.drawables)
					c.LoadContent(true);
				foreach (IDrawableAlphaComponent c in this.alphaDrawables)
					c.LoadContent(true);
				foreach (IDrawablePostAlphaComponent c in this.postAlphaDrawables)
					c.LoadContent(true);
				foreach (IDrawablePreFrameComponent c in this.preframeDrawables)
					c.LoadContent(true);
				foreach (INonPostProcessedDrawableComponent c in this.nonPostProcessedDrawables)
					c.LoadContent(true);
				this.ReloadedContent.Execute();
			}

			this.GraphicsDevice.RasterizerState = new RasterizerState { MultiSampleAntiAlias = false };
		}
Example #7
0
        private void show(Entity entity)
        {
            foreach (DictionaryEntry entry in new DictionaryEntry[] { new DictionaryEntry("[" + entity.Type.ToString() + " entity]", entity.Properties.Concat(entity.Commands)) }
                .Union(entity.Components.Where(x => ((Component)x.Value).Editable)))
            {
                IEnumerable<DictionaryEntry> properties = null;
                if (typeof(Component).IsAssignableFrom(entry.Value.GetType()))
                    properties = entry.Value.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance)
                        .Select(x => new DictionaryEntry(x.Name, x.GetValue(entry.Value)))
                        .Concat(entry.Value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                        .Where(y => y.GetIndexParameters().Length == 0)
                        .Select(z => new DictionaryEntry(z.Name, z.GetValue(entry.Value, null))));
                else
                    properties = (IEnumerable<DictionaryEntry>)entry.Value;
                properties = properties.Where(x => x.Value != null
                    && ((x.Value.GetType() == typeof(Command) && ((Command)x.Value).ShowInEditor)
                    || (typeof(IProperty).IsAssignableFrom(x.Value.GetType()) && !typeof(IListProperty).IsAssignableFrom(x.Value.GetType()) && (bool)x.Value.GetType().GetProperty("Editable").GetValue(x.Value, null))));

                if (properties.FirstOrDefault().Value == null)
                    continue;

                Container label = this.addText(entry.Key.ToString());

                Container propertyListContainer = new Container();
                propertyListContainer.PaddingLeft.Value = 10.0f;
                propertyListContainer.PaddingRight.Value = 0.0f;
                propertyListContainer.PaddingBottom.Value = 0.0f;
                propertyListContainer.PaddingTop.Value = 0.0f;
                propertyListContainer.Opacity.Value = 0.0f;
                this.UIElements.Add(propertyListContainer);

                ListContainer propertyList = new ListContainer();
                propertyListContainer.Children.Add(propertyList);

                label.Add(new Binding<float, bool>(label.Opacity, x => x ? 1.0f : 0.5f, label.Highlighted));

                label.Add(new CommandBinding<Point>(label.MouseLeftUp, delegate(Point mouse)
                {
                    propertyListContainer.Visible.Value = !propertyListContainer.Visible;
                }));

                foreach (DictionaryEntry property in properties)
                {
                    ListContainer row = new ListContainer();
                    row.Orientation.Value = ListContainer.ListOrientation.Horizontal;

                    Container keyContainer = new Container();
                    keyContainer.Tint.Value = Color.Black;
                    keyContainer.Opacity.Value = 0.5f;
                    keyContainer.ResizeHorizontal.Value = false;
                    keyContainer.Size.Value = new Vector2(128.0f, 0.0f);
                    TextElement keyText = new TextElement();
                    keyText.FontFile.Value = "Font";
                    keyText.Text.Value = property.Key.ToString();
                    keyContainer.Children.Add(keyText);
                    row.Children.Add(keyContainer);

                    if (property.Value.GetType() == typeof(Command))
                    {
                        // It's a command
                        Container field = new Container();
                        field.Tint.Value = Color.Black;

                        field.Add(new Binding<float, bool>(field.Opacity, x => x ? 1.0f : 0.5f, field.Highlighted));

                        TextElement textField = new TextElement();
                        textField.FontFile.Value = "Font";
                        textField.Text.Value = "[Execute]";
                        field.Children.Add(textField);

                        field.Add(new CommandBinding<Point>(field.MouseLeftUp, delegate(Point p)
                        {
                            ((Command)property.Value).Execute();
                        }));

                        row.Children.Add(field);
                    }
                    else
                    {
                        // It's a property
                        PropertyInfo info = property.Value.GetType().GetProperty("Value");
                        if (info.PropertyType.Equals(typeof(Vector2)))
                        {
                            ListContainer elementList = new ListContainer();
                            elementList.Orientation.Value = ListContainer.ListOrientation.Horizontal;
                            row.Children.Add(elementList);
                            foreach (VectorElement field in new[] { VectorElement.X, VectorElement.Y })
                                elementList.Children.Add(this.buildValueMemberField(info.PropertyType, (IProperty)property.Value, field));
                        }
                        else if (info.PropertyType.Equals(typeof(Vector3)))
                        {
                            ListContainer elementList = new ListContainer();
                            elementList.Orientation.Value = ListContainer.ListOrientation.Horizontal;
                            row.Children.Add(elementList);
                            foreach (VectorElement field in new[] { VectorElement.X, VectorElement.Y, VectorElement.Z })
                                elementList.Children.Add(this.buildValueMemberField(info.PropertyType, (IProperty)property.Value, field));
                        }
                        else if (info.PropertyType.Equals(typeof(Vector4)) || info.PropertyType.Equals(typeof(Quaternion)) || info.PropertyType.Equals(typeof(Color)))
                        {
                            ListContainer elementList = new ListContainer();
                            elementList.Orientation.Value = ListContainer.ListOrientation.Horizontal;
                            row.Children.Add(elementList);
                            foreach (VectorElement field in new[] { VectorElement.X, VectorElement.Y, VectorElement.Z, VectorElement.W })
                                elementList.Children.Add(this.buildValueMemberField(info.PropertyType, (IProperty)property.Value, field));
                        }
                        else
                        {
                            UIComponent field = this.buildValueField((IProperty)property.Value, info);
                            row.Children.Add(field);
                        }
                    }

                    propertyList.Children.Add(row);
                }
            }
        }
Example #8
0
		public static void Transition(Main main, string nextMap, string spawn = null)
		{
			Container loadingNotification = new Container();
			loadingNotification.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			loadingNotification.Opacity.Value = UIFactory.Opacity;
			TextElement loadingNotificationText = new TextElement();
			loadingNotificationText.Name.Value = "Text";
			loadingNotificationText.FontFile.Value = main.Font;
			loadingNotificationText.Text.Value = "\\loading";
			loadingNotification.Children.Add(loadingNotificationText);

			Animation anim = new Animation
			(
				new Animation.Set<bool>(main.Menu.CanPause, false),
				main.Spawner.FlashAnimation(),
				new Animation.Execute(delegate()
				{
					main.UI.Root.GetChildByName("Notifications").Children.Add(loadingNotification);
				}),
				new Animation.Delay(0.01f),
				new Animation.Execute(delegate()
				{
#if DEMO
					if (nextMap == "forest")
					{
						main.Spawner.StartSpawnPoint.Value = "demo";
						MapLoader.Load(main, Main.MenuMap);
					}
					else
#endif
					{
						// We are exiting the map; just save the state of the map without the player.
						ListProperty<RespawnLocation> respawnLocations = PlayerDataFactory.Instance.Get<PlayerData>().RespawnLocations;
						respawnLocations.Clear();

						List<Entity> persistentEntities = main.Entities.Where((Func<Entity, bool>)MapLoader.entityIsPersistent).ToList();

						Stream stream = new MemoryStream();
						IO.MapLoader.Serializer.Serialize(stream, persistentEntities);

						foreach (Entity e in persistentEntities)
							e.Delete.Execute();

						main.Spawner.StartSpawnPoint.Value = spawn;

						if (PlayerFactory.Instance != null)
							PlayerFactory.Instance.Delete.Execute();

						main.SaveCurrentMap(null, default(Point));
						MapLoader.Load(main, nextMap);

						stream.Seek(0, SeekOrigin.Begin);
						List<Entity> entities = (List<Entity>)IO.MapLoader.Serializer.Deserialize(stream);
						foreach (Entity e in entities)
						{
							Factory<Main> factory = Factory<Main>.Get(e.Type);
							e.GUID = 0;
							factory.Bind(e, main);
							main.Add(e);
						}
						stream.Dispose();
					}
				}),
				new Animation.Delay(0.01f),
				new Animation.Execute(loadingNotification.Delete),
				new Animation.Set<bool>(main.Menu.CanPause, true),
				new Animation.Execute(main.ScheduleSave)
			);
			anim.EnabledWhenPaused = false;
			main.AddComponent(anim);
		}
Example #9
0
        private UIComponent buildValueField(IProperty property, PropertyInfo propertyInfo)
        {
            Container field = new Container();
            field.Tint.Value = Color.Black;

            field.Add(new Binding<float, bool>(field.Opacity, x => x ? 1.0f : 0.5f, field.Highlighted));

            TextElement textField = new TextElement();
            textField.FontFile.Value = "Font";
            field.Children.Add(textField);

            if (!propertyInfo.PropertyType.Equals(typeof(string)))
            {
                // Some kind of float, int, or bool
                field.Add(new CommandBinding<Point>(field.MouseLeftDown, delegate(Point mouse)
                {
                    field.SwallowMouseEvents.Value = true;
                    field.MouseLocked.Value = true;
                }));
                field.Add(new CommandBinding<Point>(field.MouseLeftUp, delegate(Point mouse)
                {
                    field.SwallowMouseEvents.Value = false;
                    field.MouseLocked.Value = false;
                }));
            }

            if (propertyInfo.PropertyType.Equals(typeof(int)))
            {
                Property<int> socket = (Property<int>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    socket.Value += scroll * (this.EnablePrecision ? 1 : 10);
                }));
                textField.Add(new Binding<string, int>(textField.Text, x => x.ToString(), socket));
            }
            else if (propertyInfo.PropertyType.Equals(typeof(float)))
            {
                Property<float> socket = (Property<float>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    socket.Value += scroll * (this.EnablePrecision ? EditorUI.precisionDelta : EditorUI.normalDelta);;
                }));
                textField.Add(new Binding<string, float>(textField.Text, x => x.ToString("F"), socket));
            }
            else if (propertyInfo.PropertyType.Equals(typeof(bool)))
            {
                Property<bool> socket = (Property<bool>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    socket.Value = !socket;
                }));
                textField.Add(new Binding<string, bool>(textField.Text, x => x.ToString(), socket));
            }
            else if (typeof(Enum).IsAssignableFrom(propertyInfo.PropertyType))
            {
                int numFields = propertyInfo.PropertyType.GetFields(BindingFlags.Static | BindingFlags.Public).Length;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    int i = (int)propertyInfo.GetValue(property, null);
                    i += scroll;
                    if (i < 0)
                        i = numFields - 1;
                    else if (i >= numFields)
                        i = 0;
                    propertyInfo.SetValue(property, Enum.ToObject(propertyInfo.PropertyType, i), null);
                }));
                textField.Add(new Binding<string>(textField.Text, () => propertyInfo.GetValue(property, null).ToString(), (IProperty)property));
            }
            else if (propertyInfo.PropertyType.Equals(typeof(string)))
            {
                Property<string> socket = (Property<string>)property;
                Binding<string> binding = new Binding<string>(textField.Text, socket);
                textField.Add(binding);
                field.Add(new CommandBinding<Point>(field.MouseLeftUp, delegate(Point mouse)
                {
                    if (this.selectedStringProperty != socket)
                    {
                        if (this.selectedStringProperty != null)
                            this.revertStringProperty();
                        this.selectedStringProperty = socket;
                        this.selectedStringDisplayProperty = textField.Text;
                        binding.Enabled = false;
                        this.selectedStringBinding = binding;
                        this.selectedStringValue = socket.Value ?? "";
                        this.selectedStringIndex = this.selectedStringValue.Length;
                        this.selectedStringDisplayProperty.Value = this.selectedStringValue.Insert(this.selectedStringIndex, "_");
                        this.StringPropertyLocked.Value = true;
                    }
                }));
            }
            else if (propertyInfo.PropertyType.Equals(typeof(Entity.Handle)))
            {
                Property<Entity.Handle> socket = (Property<Entity.Handle>)property;
                Binding<string> binding = new Binding<string>(textField.Text, () => socket.Value.ID, socket);
                textField.Add(binding);
                field.Add(new CommandBinding<Point>(field.MouseLeftUp, delegate(Point mouse)
                {
                    this.lockStringProperty(textField.Text, socket, socket.Value.ID ?? "", binding);
                }));
            }
            else if (propertyInfo.PropertyType.Equals(typeof(Matrix)))
                textField.Text.Value = "[matrix]";

            return field;
        }
Example #10
0
        private UIComponent buildValueMemberField(Type type, IProperty property, VectorElement element)
        {
            Container field = new Container();
            field.Tint.Value = Color.Black;

            field.Add(new Binding<float, bool>(field.Opacity, x => x ? 1.0f : 0.5f, field.Highlighted));

            TextElement textField = new TextElement();
            textField.FontFile.Value = "Font";
            field.Children.Add(textField);

            field.Add(new CommandBinding<Point>(field.MouseLeftDown, delegate(Point mouse)
            {
                field.SwallowMouseEvents.Value = true;
                field.MouseLocked.Value = true;
            }));
            field.Add(new CommandBinding<Point>(field.MouseLeftUp, delegate(Point mouse)
            {
                field.SwallowMouseEvents.Value = false;
                field.MouseLocked.Value = false;
            }));

            if (type.Equals(typeof(Vector2)))
            {
                Property<Vector2> socket = (Property<Vector2>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    float delta = scroll * (this.EnablePrecision ? EditorUI.precisionDelta : EditorUI.normalDelta);
                    socket.Value = socket.Value.SetElement(element, socket.Value.GetElement(element) + delta);
                }));
                textField.Add(new Binding<string, Vector2>(textField.Text, x => x.GetElement(element).ToString("F"), socket));
            }
            else if (type.Equals(typeof(Vector3)))
            {
                Property<Vector3> socket = (Property<Vector3>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    float delta = scroll * (this.EnablePrecision ? EditorUI.precisionDelta : EditorUI.normalDelta);
                    socket.Value = socket.Value.SetElement(element, socket.Value.GetElement(element) + delta);
                }));
                textField.Add(new Binding<string, Vector3>(textField.Text, x => x.GetElement(element).ToString("F"), socket));
            }
            else if (type.Equals(typeof(Vector4)))
            {
                Property<Vector4> socket = (Property<Vector4>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    float delta = scroll * (this.EnablePrecision ? EditorUI.precisionDelta : EditorUI.normalDelta);
                    socket.Value = socket.Value.SetElement(element, socket.Value.GetElement(element) + delta);
                }));
                textField.Add(new Binding<string, Vector4>(textField.Text, x => x.GetElement(element).ToString("F"), socket));
            }
            else if (type.Equals(typeof(Quaternion)))
            {
                Property<Quaternion> socket = (Property<Quaternion>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    float delta = scroll * (this.EnablePrecision ? EditorUI.precisionDelta : EditorUI.normalDelta);
                    socket.Value = socket.Value.SetElement(element, socket.Value.GetElement(element) + delta);
                }));
                textField.Add(new Binding<string, Quaternion>(textField.Text, x => x.GetElement(element).ToString("F"), socket));
            }
            else if (type.Equals(typeof(Color)))
            {
                Property<Color> socket = (Property<Color>)property;
                field.Add(new CommandBinding<Point, int>(field.MouseScrolled, () => this.selectedStringProperty == null && field.MouseLocked, delegate(Point mouse, int scroll)
                {
                    this.NeedsSave.Value = true;
                    socket.Value = socket.Value.SetElement(element, (byte)Math.Max(0, Math.Min(255, socket.Value.GetElement(element) + scroll)));
                }));
                textField.Add(new Binding<string, Color>(textField.Text, x => x.GetElement(element).ToString(), socket));
            }

            return field;
        }
Example #11
0
 private Container addText(string text)
 {
     Container container = new Container();
     container.Tint.Value = Color.Black;
     container.Opacity.Value = 0.2f;
     TextElement display = new TextElement();
     display.FontFile.Value = "Font";
     display.Text.Value = text;
     container.Children.Add(display);
     this.UIElements.Add(container);
     return container;
 }
Example #12
0
        public override void InitializeProperties()
        {
            this.SelectedEntities.ItemAdded += new ListProperty<Entity>.ItemAddedEventHandler(delegate(int index, Entity item)
            {
                this.refresh();
            });
            this.SelectedEntities.ItemRemoved += new ListProperty<Entity>.ItemRemovedEventHandler(delegate(int index, Entity item)
            {
                this.refresh();
            });
            this.SelectedEntities.ItemChanged += new ListProperty<Components.Entity>.ItemChangedEventHandler(delegate(int index, Entity old, Entity newValue)
            {
                this.refresh();
            });
            this.SelectedEntities.Cleared += new ListProperty<Components.Entity>.ClearEventHandler(this.refresh);
            this.Add(new NotifyBinding(this.refresh, this.MapEditMode));

            this.PopupVisible.Set = delegate(bool value)
            {
                if (this.PopupVisible.InternalValue && !value)
                    this.revertStringProperty();
                else if (!this.PopupVisible.InternalValue && value)
                    this.lockStringProperty(this.PopupSearchText, null, this.PopupSearchText, null, false, true);

                this.PopupVisible.InternalValue = value;
            };

            this.Add(new NotifyBinding(delegate()
            {
                string search = this.PopupSearchText.Value.ToLower().TrimEnd('_');
                bool first = true;
                foreach (Container element in this.PopupElements)
                {
                    PopupCommand command = (PopupCommand)element.UserData.Value;

                    bool visible = command.Enabled() && command.Description.ToLower().Contains(search);
                    element.Visible.Value = visible;
                    if (first && visible)
                    {
                        first = false;
                        element.Opacity.Value = 1.0f;
                    }
                    else
                        element.Opacity.Value = 0.0f;
                }
            }, () => this.PopupVisible, this.PopupVisible, this.PopupSearchText));

            this.Add(new ListBinding<UIComponent, PopupCommand>(this.PopupElements, this.PopupCommands, delegate(PopupCommand command)
            {
                Container container = new Container();
                container.UserData.Value = command;
                container.Tint.Value = Color.Black;
                container.Add(new Binding<float, bool>(container.Opacity, x => x ? 1.0f : 0.0f, container.Highlighted));
                container.Add(new CommandBinding<Point>(container.MouseLeftUp, delegate(Point p)
                {
                    this.PopupVisible.Value = false;
                    command.Action.Execute();
                }));

                ListContainer layout = new ListContainer();
                layout.Orientation.Value = ListContainer.ListOrientation.Horizontal;
                container.Children.Add(layout);

                Container descriptionContainer = new Container();
                descriptionContainer.Opacity.Value = 0.0f;
                descriptionContainer.ResizeHorizontal.Value = false;
                descriptionContainer.Size.Value = new Vector2(110.0f, 0.0f);
                descriptionContainer.EnableScissor.Value = true;
                layout.Children.Add(descriptionContainer);
                TextElement description = new TextElement();
                description.Name.Value = "Description";
                description.FontFile.Value = "Font";
                description.Text.Value = command.Description;
                descriptionContainer.Children.Add(description);

                if (command.Chord.Key != Keys.None)
                {
                    Container chordContainer = new Container();
                    chordContainer.Opacity.Value = 0.0f;
                    layout.Children.Add(chordContainer);
                    TextElement chord = new TextElement();
                    chord.FontFile.Value = "Font";
                    if (command.Chord.Modifier != Keys.None)
                        chord.Text.Value = command.Chord.Modifier.ToString() + " " + command.Chord.Key.ToString();
                    else
                        chord.Text.Value = command.Chord.Key.ToString();
                    chordContainer.Children.Add(chord);
                }

                return new[] { container };
            }));
        }
Example #13
0
 private static Container buildMessage()
 {
     Container msgBackground = new Container();
     ((GameMain)main).UI.Root.GetChildByName("Messages").Children.Add(msgBackground);
     msgBackground.Tint.Value = Color.Black;
     msgBackground.Opacity.Value = 0.0f;
     TextElement msg = new TextElement();
     msg.FontFile.Value = "Font";
     msg.Opacity.Value = 0.0f;
     msg.WrapWidth.Value = 250.0f;
     msgBackground.Children.Add(msg);
     WorldFactory.Get().Add(msgBackground);
     return msgBackground;
 }
Example #14
0
        public override void Bind(Entity result, Main main, bool creating = false)
        {
            this.SetMain(result, main);
            Editor editor = result.Get<Editor>();
            EditorUI ui = result.Get<EditorUI>();
            Model model = result.Get<Model>("Model");
            FPSInput input = result.Get<FPSInput>("Input");
            UIRenderer uiRenderer = result.Get<UIRenderer>();

            ModelAlpha radiusVisual = new ModelAlpha();
            radiusVisual.Filename.Value = "Models\\alpha-sphere";
            radiusVisual.Color.Value = new Vector3(1.0f);
            radiusVisual.Alpha.Value = 0.1f;
            radiusVisual.Editable = false;
            radiusVisual.Serialize = false;
            radiusVisual.DrawOrder.Value = 11; // In front of water
            radiusVisual.DisableCulling.Value = true;
            result.Add(radiusVisual);
            radiusVisual.Add(new Binding<Matrix, Vector3>(radiusVisual.Transform, x => Matrix.CreateTranslation(x), editor.Position));
            radiusVisual.Add(new Binding<Vector3, int>(radiusVisual.Scale, x => new Vector3(x), editor.BrushSize));
            radiusVisual.Add(new Binding<bool>(radiusVisual.Enabled, () => editor.BrushSize > 1 && editor.MapEditMode, editor.BrushSize, editor.MapEditMode));
            radiusVisual.CullBoundingBox.Value = false;

            ModelAlpha selection = new ModelAlpha();
            selection.Filename.Value = "Models\\alpha-box";
            selection.Color.Value = new Vector3(1.0f, 0.7f, 0.4f);
            selection.Alpha.Value = 0.25f;
            selection.Editable = false;
            selection.Serialize = false;
            selection.DrawOrder.Value = 12; // In front of water and radius visualizer
            selection.DisableCulling.Value = true;
            result.Add(selection);
            selection.Add(new Binding<bool>(selection.Enabled, editor.VoxelSelectionActive));
            selection.Add(new Binding<Matrix>(selection.Transform, delegate()
            {
                const float padding = 0.1f;
                Map map = editor.SelectedEntities[0].Get<Map>();
                Vector3 start = map.GetRelativePosition(editor.VoxelSelectionStart) - new Vector3(0.5f), end = map.GetRelativePosition(editor.VoxelSelectionEnd) - new Vector3(0.5f);
                return Matrix.CreateScale((end - start) + new Vector3(padding)) * Matrix.CreateTranslation((start + end) * 0.5f) * map.Transform;
            }, () => selection.Enabled, editor.VoxelSelectionStart, editor.VoxelSelectionEnd));
            selection.CullBoundingBox.Value = false;

            Action<string, PCInput.Chord, Func<bool>, Command> addCommand = delegate(string description, PCInput.Chord chord, Func<bool> enabled, Command action)
            {
                ui.PopupCommands.Add(new EditorUI.PopupCommand { Description = description, Chord = chord, Enabled = enabled, Action = action });

                if (chord.Modifier != Keys.None)
                    input.Add(new CommandBinding(input.GetChord(chord), () => enabled() && !ui.StringPropertyLocked, action));
                else
                    input.Add(new CommandBinding(input.GetKeyDown(chord.Key), () => enabled() && !ui.StringPropertyLocked, action));

                ui.Add(new CommandBinding(action, delegate()
                {
                    Container container = new Container();
                    container.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                    container.Opacity.Value = 0.2f;
                    container.AnchorPoint.Value = new Vector2(1.0f, 0.0f);
                    container.Add(new Binding<Vector2, Point>(container.Position, x => new Vector2(x.X - 10.0f, 10.0f), main.ScreenSize));
                    TextElement display = new TextElement();
                    display.FontFile.Value = "Font";
                    display.Text.Value = description;
                    container.Children.Add(display);
                    uiRenderer.Root.Children.Add(container);
                    main.AddComponent(new Animation
                    (
                        new Animation.Parallel
                        (
                            new Animation.FloatMoveTo(container.Opacity, 0.0f, 1.0f),
                            new Animation.FloatMoveTo(display.Opacity, 0.0f, 1.0f)
                        ),
                        new Animation.Execute(delegate() { uiRenderer.Root.Children.Remove(container); })
                    ));
                }));
            };

            foreach (string key in Factory.factories.Keys)
            {
                string entityType = key;
                ui.PopupCommands.Add(new EditorUI.PopupCommand
                {
                    Description = "Add " + entityType,
                    Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode,
                    Action = new Command { Action = () => editor.Spawn.Execute(entityType) },
                });
            }

            Scroller scroller = (Scroller)uiRenderer.Root.GetChildByName("Scroller");

            Container popup = (Container)uiRenderer.Root.GetChildByName("Popup");
            ListContainer popupList = (ListContainer)popup.GetChildByName("PopupList");

            input.Add(new CommandBinding(input.GetKeyUp(Keys.Space), () => !editor.MapEditMode && !ui.StringPropertyLocked && !editor.MovementEnabled, delegate()
            {
                Vector2 pos = input.Mouse;
                pos.X = Math.Min(main.ScreenSize.Value.X - popup.Size.Value.X, pos.X);
                pos.Y = Math.Min(main.ScreenSize.Value.Y - popup.Size.Value.Y, pos.Y);
                popup.Position.Value = pos;
                ui.PopupVisible.Value = true;
            }));

            input.Add(new CommandBinding(input.GetKeyUp(Keys.Escape), () => ui.PopupVisible, delegate()
            {
                if (ui.PopupSearchText.Value == "_")
                    ui.PopupVisible.Value = false;
                else
                    ui.ClearSelectedStringProperty();
            }));

            input.Add(new CommandBinding(input.RightMouseButtonUp, () => ui.PopupVisible, delegate()
            {
                ui.PopupVisible.Value = false;
            }));

            uiRenderer.Add(new Binding<bool>(popup.Visible, ui.PopupVisible));
            uiRenderer.Add(new Binding<string>(((TextElement)popup.GetChildByName("PopupSearch")).Text, ui.PopupSearchText));
            uiRenderer.Add(new ListBinding<UIComponent>(popupList.Children, ui.PopupElements));

            AudioListener audioListener = result.Get<AudioListener>();
            audioListener.Add(new Binding<Vector3>(audioListener.Position, main.Camera.Position));
            audioListener.Add(new Binding<Vector3>(audioListener.Forward, main.Camera.Forward));

            model.Add(new Binding<bool>(model.Enabled, editor.MapEditMode));
            model.Add(new Binding<Matrix>(model.Transform, () => editor.Orientation.Value * Matrix.CreateTranslation(editor.Position), editor.Position, editor.Orientation));

            editor.Add(new TwoWayBinding<string>(main.MapFile, editor.MapFile));

            result.Add(new TwoWayBinding<string>(((GameMain)main).StartSpawnPoint, result.GetProperty<string>("StartSpawnPoint")));

            uiRenderer.Add(new ListBinding<UIComponent>(uiRenderer.Root.GetChildByName("PropertyList").Children, ui.UIElements));
            ui.Add(new ListBinding<Entity>(ui.SelectedEntities, editor.SelectedEntities));
            ui.Add(new Binding<bool>(ui.MapEditMode, editor.MapEditMode));
            ui.Add(new Binding<bool>(ui.EnablePrecision, x => !x, input.GetKey(Keys.LeftShift)));
            editor.Add(new Binding<bool>(editor.MovementEnabled, () => !ui.StringPropertyLocked && (input.MiddleMouseButton || editor.MapEditMode), ui.StringPropertyLocked, input.MiddleMouseButton, editor.MapEditMode));
            ui.Add(new TwoWayBinding<bool>(editor.NeedsSave, ui.NeedsSave));

            editor.Add(new Binding<Vector2>(editor.Movement, input.Movement));
            editor.Add(new Binding<bool>(editor.Up, input.GetKey(Keys.Space)));
            editor.Add(new Binding<bool>(editor.Down, input.GetKey(Keys.LeftControl)));
            editor.Add(new Binding<bool>(editor.Empty, input.RightMouseButton));
            editor.Add(new Binding<bool>(editor.SpeedMode, input.GetKey(Keys.LeftShift)));
            editor.Add(new Binding<bool>(editor.Extend, input.GetKey(Keys.F)));
            editor.Add(new Binding<bool>(editor.Fill, input.LeftMouseButton));
            editor.Add(new Binding<bool>(editor.EditSelection, () => input.MiddleMouseButton && editor.MapEditMode, input.MiddleMouseButton, editor.MapEditMode));

            addCommand("Delete", new PCInput.Chord { Key = Keys.X }, () => !editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None && editor.SelectedEntities.Count > 0, editor.DeleteSelected);
            addCommand("Duplicate", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.D }, () => !editor.MovementEnabled && editor.SelectedEntities.Count > 0, editor.Duplicate);

            // Start playing
            addCommand("Run", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.R }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    if (editor.NeedsSave)
                        editor.Save.Execute();
                    main.EditorEnabled.Value = false;
                    IO.MapLoader.Load(main, null, main.MapFile);
                }
            });

            result.Add(new CommandBinding(main.MapLoaded, delegate()
            {
                editor.Position.Value = Vector3.Zero;
                editor.NeedsSave.Value = false;
            }));

            addCommand("Quit", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.Q }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    throw new GameMain.ExitException();
                }
            });

            Property<bool> analyticsEnable = new Property<bool>();
            ListProperty<SessionEntry> analyticsSessions = new ListProperty<SessionEntry>();
            ListProperty<SessionEntry> analyticsActiveSessions = new ListProperty<SessionEntry>();
            ListProperty<EventEntry> analyticsEvents = new ListProperty<EventEntry>();
            ListProperty<EventEntry> analyticsActiveEvents = new ListProperty<EventEntry>();
            ListProperty<PropertyEntry> analyticsProperties = new ListProperty<PropertyEntry>();
            ListProperty<PropertyEntry> analyticsActiveProperties = new ListProperty<PropertyEntry>();
            Dictionary<Session, ModelInstance> sessionPositionModels = new Dictionary<Session, ModelInstance>();
            Dictionary<Session.EventList, List<ModelInstance>> eventPositionModels = new Dictionary<Session.EventList, List<ModelInstance>>();
            Property<bool> analyticsPlaying = new Property<bool>();
            Property<float> playbackSpeed = new Property<float> { Value = 1.0f };
            Property<float> playbackLocation = new Property<float>();

            const float timelineHeight = 32.0f;

            Scroller timelineScroller = new Scroller();
            timelineScroller.ScrollAmount.Value = 60.0f;
            timelineScroller.EnableScissor.Value = false;
            timelineScroller.DefaultScrollHorizontal.Value = true;
            timelineScroller.AnchorPoint.Value = new Vector2(0, 1);
            timelineScroller.ResizeVertical.Value = true;
            timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Position, x => new Vector2(0, x.Y), main.ScreenSize));
            timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Size, x => new Vector2(x.X, timelineHeight), main.ScreenSize));
            timelineScroller.Add(new Binding<bool>(timelineScroller.Visible, analyticsEnable));
            timelineScroller.Add(new Binding<bool>(timelineScroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
            uiRenderer.Root.Children.Add(timelineScroller);

            scroller.Add(new Binding<Vector2>(scroller.Size, () => new Vector2(scroller.Size.Value.X, main.ScreenSize.Value.Y - 20 - timelineScroller.ScaledSize.Value.Y), main.ScreenSize, timelineScroller.ScaledSize));

            ListContainer timelines = new ListContainer();
            timelines.Alignment.Value = ListContainer.ListAlignment.Min;
            timelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
            timelines.Reversed.Value = true;
            timelineScroller.Children.Add(timelines);

            Container timeline = new Container();
            timeline.Size.Value = new Vector2(0, timelineHeight);
            timeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            timeline.ResizeHorizontal.Value = false;
            timeline.ResizeVertical.Value = false;
            timelines.Children.Add(timeline);

            ui.PopupCommands.Add(new EditorUI.PopupCommand
            {
                Description = "Load analytics data",
                Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode && !analyticsEnable,
                Action = new Command
                {
                    Action = delegate()
                    {
                        if (main.MapFile.Value != null)
                        {
                            List<Session> sessions = ((GameMain)main).LoadAnalytics(main.MapFile);
                            if (sessions.Count > 0)
                            {
                                analyticsEnable.Value = true;
                                Dictionary<string, bool> distinctEventNames = new Dictionary<string, bool>();
                                Dictionary<string, bool> distinctPropertyNames = new Dictionary<string, bool>();
                                foreach (Session s in sessions)
                                {
                                    foreach (Session.EventList el in s.Events)
                                    {
                                        distinctEventNames[el.Name] = true;
                                        s.TotalTime = Math.Max(s.TotalTime, el.Events[el.Events.Count - 1].Time);
                                    }
                                    foreach (Session.ContinuousProperty p in s.ContinuousProperties)
                                    {
                                        if (p.Independent)
                                            distinctPropertyNames[p.Name] = true;
                                    }
                                    analyticsSessions.Add(new SessionEntry { Session = s });
                                }
                                analyticsEvents.Add(distinctEventNames.Keys.Select(x => new EventEntry { Name = x }));
                                analyticsProperties.Add(distinctPropertyNames.Keys.Select(x => new PropertyEntry { Name = x }));
                                timeline.Size.Value = new Vector2(analyticsSessions.Max(x => x.Session.TotalTime), timelineScroller.Size.Value.Y);
                                timelines.Scale.Value = new Vector2(timelineScroller.Size.Value.X / timeline.Size.Value.X, 1.0f);
                            }
                        }
                    }
                },
            });

            ListContainer sessionsSidebar = new ListContainer();
            sessionsSidebar.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Add(new Binding<Vector2>(sessionsSidebar.Position, () => new Vector2(main.ScreenSize.Value.X - 10, main.ScreenSize.Value.Y - timelineScroller.ScaledSize.Value.Y - 10), main.ScreenSize, timelineScroller.ScaledSize));
            sessionsSidebar.Add(new Binding<bool>(sessionsSidebar.Visible, analyticsEnable));
            sessionsSidebar.Alignment.Value = ListContainer.ListAlignment.Max;
            sessionsSidebar.Reversed.Value = true;
            uiRenderer.Root.Children.Add(sessionsSidebar);

            Func<string, ListContainer> createCheckboxListItem = delegate(string text)
            {
                ListContainer layout = new ListContainer();
                layout.Orientation.Value = ListContainer.ListOrientation.Horizontal;

                TextElement label = new TextElement();
                label.FontFile.Value = "Font";
                label.Text.Value = text;
                label.Name.Value = "Label";
                layout.Children.Add(label);

                Container checkboxContainer = new Container();
                checkboxContainer.PaddingBottom.Value = checkboxContainer.PaddingLeft.Value = checkboxContainer.PaddingRight.Value = checkboxContainer.PaddingTop.Value = 1.0f;
                layout.Children.Add(checkboxContainer);

                Container checkbox = new Container();
                checkbox.Name.Value = "Checkbox";
                checkbox.ResizeHorizontal.Value = checkbox.ResizeVertical.Value = false;
                checkbox.Size.Value = new Vector2(16.0f, 16.0f);
                checkboxContainer.Children.Add(checkbox);
                return layout;
            };

            Container sessionsContainer = new Container();
            sessionsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            sessionsContainer.Opacity.Value = 0.5f;
            sessionsContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(sessionsContainer);

            Scroller sessionsScroller = new Scroller();
            sessionsScroller.ResizeHorizontal.Value = true;
            sessionsScroller.ResizeVertical.Value = true;
            sessionsScroller.MaxVerticalSize.Value = 256;
            sessionsContainer.Children.Add(sessionsScroller);

            ListContainer sessionList = new ListContainer();
            sessionList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            sessionList.Alignment.Value = ListContainer.ListAlignment.Max;
            sessionsScroller.Children.Add(sessionList);

            Property<bool> allSessions = new Property<bool>();

            sessionList.Add(new ListBinding<UIComponent, SessionEntry>(sessionList.Children, analyticsSessions, delegate(SessionEntry entry)
            {
                ListContainer item = createCheckboxListItem(entry.Session.Date.ToShortDateString() + " (" + new TimeSpan(0, 0, (int)entry.Session.TotalTime).ToString() + ")");

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, entry.Active));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (entry.Active)
                    {
                        allSessions.Value = false;
                        analyticsActiveSessions.Remove(entry);
                    }
                    else
                        analyticsActiveSessions.Add(entry);
                }));

                return new[] { item };
            }));

            ListContainer allSessionsButton = createCheckboxListItem("[All]");
            allSessionsButton.Add(new CommandBinding<Point>(allSessionsButton.MouseLeftDown, delegate(Point p)
            {
                if (allSessions)
                {
                    allSessions.Value = false;
                    foreach (SessionEntry s in analyticsActiveSessions.ToList())
                        analyticsActiveSessions.Remove(s);
                }
                else
                {
                    allSessions.Value = true;
                    foreach (SessionEntry s in analyticsSessions)
                    {
                        if (!s.Active)
                            analyticsActiveSessions.Add(s);
                    }
                }
            }));

            Container allSessionsCheckbox = (Container)allSessionsButton.GetChildByName("Checkbox");
            allSessionsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allSessionsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allSessions));
            sessionList.Children.Add(allSessionsButton);

            Container eventsContainer = new Container();
            eventsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            eventsContainer.Opacity.Value = 0.5f;
            eventsContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(eventsContainer);

            Scroller eventsScroller = new Scroller();
            eventsScroller.ResizeHorizontal.Value = true;
            eventsScroller.ResizeVertical.Value = true;
            eventsScroller.MaxVerticalSize.Value = 256;
            eventsContainer.Children.Add(eventsScroller);

            ListContainer eventList = new ListContainer();
            eventList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            eventList.Alignment.Value = ListContainer.ListAlignment.Max;
            eventsScroller.Children.Add(eventList);

            Property<bool> allEvents = new Property<bool>();

            eventList.Add(new ListBinding<UIComponent, EventEntry>(eventList.Children, analyticsEvents, delegate(EventEntry e)
            {
                ListContainer item = createCheckboxListItem(e.Name);

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

                TextElement label = (TextElement)item.GetChildByName("Label");
                label.Tint.Value = new Microsoft.Xna.Framework.Color(this.colorHash(e.Name));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (e.Active)
                    {
                        allEvents.Value = false;
                        analyticsActiveEvents.Remove(e);
                    }
                    else
                        analyticsActiveEvents.Add(e);
                }));

                return new[] { item };
            }));

            ListContainer allEventsButton = createCheckboxListItem("[All]");
            allEventsButton.Add(new CommandBinding<Point>(allEventsButton.MouseLeftDown, delegate(Point p)
            {
                if (allEvents)
                {
                    allEvents.Value = false;
                    foreach (EventEntry e in analyticsActiveEvents.ToList())
                        analyticsActiveEvents.Remove(e);
                }
                else
                {
                    allEvents.Value = true;
                    foreach (EventEntry e in analyticsEvents)
                    {
                        if (!e.Active)
                            analyticsActiveEvents.Add(e);
                    }
                }
            }));
            Container allEventsCheckbox = (Container)allEventsButton.GetChildByName("Checkbox");
            allEventsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allEventsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allEvents));
            eventList.Children.Add(allEventsButton);

            Container propertiesContainer = new Container();
            propertiesContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            propertiesContainer.Opacity.Value = 0.5f;
            propertiesContainer.AnchorPoint.Value = new Vector2(1, 1);
            sessionsSidebar.Children.Add(propertiesContainer);

            Scroller propertiesScroller = new Scroller();
            propertiesScroller.ResizeHorizontal.Value = true;
            propertiesScroller.ResizeVertical.Value = true;
            propertiesScroller.MaxVerticalSize.Value = 256;
            propertiesContainer.Children.Add(propertiesScroller);

            ListContainer propertiesList = new ListContainer();
            propertiesList.Orientation.Value = ListContainer.ListOrientation.Vertical;
            propertiesList.Alignment.Value = ListContainer.ListAlignment.Max;
            propertiesScroller.Children.Add(propertiesList);

            Property<bool> allProperties = new Property<bool>();

            propertiesList.Add(new ListBinding<UIComponent, PropertyEntry>(propertiesList.Children, analyticsProperties, delegate(PropertyEntry e)
            {
                ListContainer item = createCheckboxListItem(e.Name);

                Container checkbox = (Container)item.GetChildByName("Checkbox");
                checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

                TextElement label = (TextElement)item.GetChildByName("Label");
                label.Tint.Value = new Microsoft.Xna.Framework.Color(this.colorHash(e.Name));

                item.Add(new CommandBinding<Point>(item.MouseLeftDown, delegate(Point p)
                {
                    if (e.Active)
                    {
                        allProperties.Value = false;
                        analyticsActiveProperties.Remove(e);
                    }
                    else
                        analyticsActiveProperties.Add(e);
                }));

                return new[] { item };
            }));

            ListContainer allPropertiesButton = createCheckboxListItem("[All]");
            allPropertiesButton.Add(new CommandBinding<Point>(allPropertiesButton.MouseLeftDown, delegate(Point p)
            {
                if (allProperties)
                {
                    allProperties.Value = false;
                    foreach (PropertyEntry e in analyticsActiveProperties.ToList())
                        analyticsActiveProperties.Remove(e);
                }
                else
                {
                    allProperties.Value = true;
                    foreach (PropertyEntry e in analyticsProperties)
                    {
                        if (!e.Active)
                            analyticsActiveProperties.Add(e);
                    }
                }
            }));
            Container allPropertiesCheckbox = (Container)allPropertiesButton.GetChildByName("Checkbox");
            allPropertiesCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allPropertiesCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allProperties));
            propertiesList.Children.Add(allPropertiesButton);

            Func<Session.EventList, LineDrawer2D> createEventLines = delegate(Session.EventList el)
            {
                LineDrawer2D line = new LineDrawer2D();
                line.Color.Value = this.colorHash(el.Name);
                line.UserData.Value = el;

                foreach (Session.Event e in el.Events)
                {
                    line.Lines.Add(new LineDrawer2D.Line
                    {
                        A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, 0.0f, 0.0f), Microsoft.Xna.Framework.Color.White),
                        B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, timeline.Size.Value.Y, 0.0f), Microsoft.Xna.Framework.Color.White),
                    });
                }
                return line;
            };

            analyticsActiveEvents.ItemAdded += delegate(int index, EventEntry ee)
            {
                ee.Active.Value = true;
                foreach (SessionEntry s in analyticsActiveSessions)
                {
                    Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
                    foreach (Session.EventList el in s.Session.Events)
                    {
                        if (el.Name == ee.Name)
                        {
                            List<ModelInstance> models = new List<ModelInstance>();
                            Vector4 color = this.colorHash(el.Name);
                            int hash = (int)(new Color(color).PackedValue);
                            foreach (Session.Event e in el.Events)
                            {
                                ModelInstance i = new ModelInstance();
                                i.Setup("Models\\position-model", hash);
                                if (i.IsFirstInstance)
                                    i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
                                i.Scale.Value = new Vector3(0.25f);
                                i.Transform.Value = Matrix.CreateTranslation(positionProperty[e.Time]);
                                models.Add(i);
                                result.Add(i);
                            }
                            eventPositionModels[el] = models;
                        }
                    }

                    timeline.Children.Add(s.Session.Events.Where(x => x.Name == ee.Name).Select(createEventLines));
                }
            };

            analyticsActiveEvents.ItemRemoved += delegate(int index, EventEntry e)
            {
                e.Active.Value = false;
                foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
                {
                    if (pair.Key.Name == e.Name)
                    {
                        foreach (ModelInstance instance in pair.Value)
                            instance.Delete.Execute();
                        eventPositionModels.Remove(pair.Key);
                    }
                }
                timeline.Children.Remove(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Name == e.Name).ToList());
            };

            analyticsActiveProperties.ItemAdded += delegate(int index, PropertyEntry e)
            {
                e.Active.Value = true;
            };

            analyticsActiveProperties.ItemRemoved += delegate(int index, PropertyEntry e)
            {
                e.Active.Value = false;
            };

            ListContainer propertyTimelines = new ListContainer();
            propertyTimelines.Alignment.Value = ListContainer.ListAlignment.Min;
            propertyTimelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
            timelines.Children.Add(propertyTimelines);

            Action<LineDrawer2D> refreshPropertyGraph = delegate(LineDrawer2D lines)
            {
                string propertyName = ((PropertyEntry)lines.UserData.Value).Name;
                lines.Lines.Clear();
                float time = 0.0f, lastTime = 0.0f;
                float lastValue = 0.0f;
                bool firstLine = true;
                float max = float.MinValue, min = float.MaxValue;
                while (true)
                {
                    bool stop = true;

                    // Calculate average
                    int count = 0;
                    float sum = 0.0f;
                    foreach (SessionEntry s in analyticsActiveSessions)
                    {
                        if (time < s.Session.TotalTime)
                        {
                            Session.ContinuousProperty prop = s.Session.GetContinuousProperty(propertyName);
                            if (prop != null)
                            {
                                stop = false;
                                sum += prop[time];
                                count++;
                            }
                        }
                    }

                    if (stop)
                        break;
                    else
                    {
                        float value = sum / (float)count;
                        if (firstLine)
                            firstLine = false;
                        else
                        {
                            lines.Lines.Add(new LineDrawer2D.Line
                            {
                                A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                                {
                                    Color = Microsoft.Xna.Framework.Color.White,
                                    Position = new Vector3(lastTime, lastValue, 0.0f),
                                },
                                B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                                {
                                    Color = Microsoft.Xna.Framework.Color.White,
                                    Position = new Vector3(time, value, 0.0f),
                                },
                            });
                        }
                        min = Math.Min(min, value);
                        max = Math.Max(max, value);
                        lastValue = value;
                        lastTime = time;
                        time += Session.Recorder.Interval;
                    }

                    if (min < max)
                    {
                        float scale = -timelineHeight / (max - min);
                        lines.Scale.Value = new Vector2(1, scale);
                        lines.Position.Value = new Vector2(0, max * -scale);
                    }
                    else
                    {
                        lines.AnchorPoint.Value = Vector2.Zero;
                        if (min <= 0.0f)
                            lines.Position.Value = new Vector2(0, timelineHeight);
                        else
                            lines.Position.Value = new Vector2(0, timelineHeight * 0.5f);
                    }
                }
            };

            Action refreshPropertyGraphs = delegate()
            {
                foreach (LineDrawer2D line in propertyTimelines.Children.Select(x => x.Children.First()))
                    refreshPropertyGraph(line);
            };

            propertyTimelines.Add(new ListBinding<UIComponent, PropertyEntry>(propertyTimelines.Children, analyticsActiveProperties, delegate(PropertyEntry e)
            {
                Container propertyTimeline = new Container();
                propertyTimeline.Add(new Binding<Vector2>(propertyTimeline.Size, timeline.Size));
                propertyTimeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                propertyTimeline.Opacity.Value = 0.5f;
                propertyTimeline.ResizeHorizontal.Value = false;
                propertyTimeline.ResizeVertical.Value = false;

                LineDrawer2D line = new LineDrawer2D();
                line.Color.Value = this.colorHash(e.Name);
                line.UserData.Value = e;
                propertyTimeline.Children.Add(line);

                refreshPropertyGraph(line);

                return new[] { propertyTimeline };
            }));

            analyticsActiveSessions.ItemAdded += delegate(int index, SessionEntry s)
            {
                Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
                foreach (Session.EventList el in s.Session.Events)
                {
                    if (analyticsActiveEvents.FirstOrDefault(x => x.Name == el.Name) != null)
                    {
                        List<ModelInstance> models = new List<ModelInstance>();
                        Vector4 color = this.colorHash(el.Name);
                        int hash = (int)(new Color(color).PackedValue);
                        foreach (Session.Event e in el.Events)
                        {
                            ModelInstance i = new ModelInstance();
                            i.Setup("Models\\position-model", hash);
                            if (i.IsFirstInstance)
                                i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
                            i.Scale.Value = new Vector3(0.25f);
                            i.Transform.Value = Matrix.CreateTranslation(positionProperty[e.Time]);
                            result.Add(i);
                            models.Add(i);
                        }
                        eventPositionModels[el] = models;
                    }
                }

                ModelInstance instance = new ModelInstance();
                instance.Setup("Models\\position-model", 0);
                instance.Scale.Value = new Vector3(0.25f);
                result.Add(instance);
                sessionPositionModels.Add(s.Session, instance);
                s.Active.Value = true;
                timeline.Children.Add(s.Session.Events.Where(x => analyticsActiveEvents.FirstOrDefault(y => y.Name == x.Name) != null).Select(createEventLines));
                playbackLocation.Reset();

                refreshPropertyGraphs();
            };

            analyticsActiveSessions.ItemRemoved += delegate(int index, SessionEntry s)
            {
                ModelInstance instance = sessionPositionModels[s.Session];
                instance.Delete.Execute();

                foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
                {
                    if (pair.Key.Session == s.Session)
                    {
                        foreach (ModelInstance i in pair.Value)
                            i.Delete.Execute();
                        eventPositionModels.Remove(pair.Key);
                    }
                }

                sessionPositionModels.Remove(s.Session);
                s.Active.Value = false;
                timeline.Children.Remove(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Session == s.Session).ToList());

                refreshPropertyGraphs();
            };

            playbackLocation.Set = delegate(float value)
            {
                if (analyticsActiveSessions.Count == 0)
                    return;

                value = Math.Max(0.0f, value);
                float end = analyticsActiveSessions.Max(x => x.Session.TotalTime);
                if (value > end)
                {
                    playbackLocation.InternalValue = end;
                    analyticsPlaying.Value = false;
                }
                else
                    playbackLocation.InternalValue = value;

                foreach (KeyValuePair<Session, ModelInstance> pair in sessionPositionModels)
                    pair.Value.Transform.Value = Matrix.CreateTranslation(pair.Key.PositionProperties[0][playbackLocation]);
            };

            LineDrawer2D playbackLine = new LineDrawer2D();
            playbackLine.Color.Value = Vector4.One;
            playbackLine.Lines.Add(new LineDrawer2D.Line
            {
                A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                {
                    Color = Microsoft.Xna.Framework.Color.White,
                    Position = new Vector3(0.0f, -10.0f, 0.0f),
                },
                B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
                {
                    Color = Microsoft.Xna.Framework.Color.White,
                    Position = new Vector3(0.0f, timeline.Size.Value.Y, 0.0f),
                },
            });
            playbackLine.Add(new Binding<Vector2, float>(playbackLine.Position, x => new Vector2(x, 0.0f), playbackLocation));
            timeline.Children.Add(playbackLine);

            result.Add(new NotifyBinding(delegate()
            {
                allEventsButton.Detach();
                allSessionsButton.Detach();
                allPropertiesButton.Detach();
                analyticsSessions.Clear();
                analyticsEvents.Clear();
                analyticsProperties.Clear();
                eventList.Children.Add(allEventsButton);
                sessionList.Children.Add(allSessionsButton);
                propertiesList.Children.Add(allPropertiesButton);

                foreach (ModelInstance instance in sessionPositionModels.Values)
                    instance.Delete.Execute();
                sessionPositionModels.Clear();

                foreach (ModelInstance instance in eventPositionModels.Values.SelectMany(x => x))
                    instance.Delete.Execute();
                eventPositionModels.Clear();

                allEvents.Value = false;
                allSessions.Value = false;
                allProperties.Value = false;
                analyticsEnable.Value = false;

                analyticsActiveEvents.Clear();
                analyticsActiveSessions.Clear();
                analyticsActiveProperties.Clear();

                propertyTimelines.Children.Clear();

                playbackLine.Detach();
                timeline.Children.Clear();
                timeline.Children.Add(playbackLine);

                analyticsPlaying.Value = false;
                playbackLocation.Value = 0.0f;
            }, main.MapFile));

            addCommand("Toggle analytics playback", new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.A }, () => analyticsEnable && !editor.MovementEnabled && analyticsActiveSessions.Count > 0, new Command
            {
                Action = delegate()
                {
                    analyticsPlaying.Value = !analyticsPlaying;
                }
            });

            addCommand("Stop analytics playback", new PCInput.Chord { Key = Keys.Escape }, () => analyticsPlaying, new Command
            {
                Action = delegate()
                {
                    analyticsPlaying.Value = false;
                }
            });

            Container playbackContainer = new Container();
            playbackContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
            playbackContainer.Opacity.Value = 0.5f;
            sessionsSidebar.Children.Add(playbackContainer);
            playbackContainer.Add(new CommandBinding<Point, int>(playbackContainer.MouseScrolled, delegate(Point p, int delta)
            {
                playbackSpeed.Value = Math.Max(1.0f, Math.Min(10.0f, playbackSpeed.Value + delta));
            }));

            TextElement playbackLabel = new TextElement();
            playbackLabel.FontFile.Value = "Font";
            playbackLabel.Add(new Binding<string>(playbackLabel.Text, delegate()
            {
                return playbackLocation.Value.ToString("F") + " " + (analyticsPlaying ? "Playing" : "Stopped") + " " + playbackSpeed.Value.ToString("F") + "x";
            }, playbackLocation, playbackSpeed, analyticsPlaying));
            playbackContainer.Children.Add(playbackLabel);

            Container descriptionContainer = null;

            Updater timelineUpdate = new Updater
            {
                delegate(float dt)
                {
                    bool setTimelinePosition = false;

                    if (timelines.Highlighted || descriptionContainer != null)
                    {
                        if (input.LeftMouseButton)
                        {
                            setTimelinePosition = true;
                            playbackLocation.Value = Vector3.Transform(new Vector3(input.Mouse.Value.X, 0.0f, 0.0f), Matrix.Invert(timeline.GetAbsoluteTransform())).X;
                        }

                        float threshold = 3.0f / timelines.Scale.Value.X;
                        float mouseRelative = Vector3.Transform(new Vector3(input.Mouse, 0.0f), Matrix.Invert(timelines.GetAbsoluteTransform())).X;

                        if (descriptionContainer != null)
                        {
                            if (!timelines.Highlighted || (float)Math.Abs(descriptionContainer.Position.Value.X - mouseRelative) > threshold)
                            {
                                descriptionContainer.Delete.Execute();
                                descriptionContainer = null;
                            }
                        }

                        if (descriptionContainer == null && timeline.Highlighted)
                        {
                            bool stop = false;
                            foreach (UIComponent component in timeline.Children)
                            {
                                LineDrawer2D lines = component as LineDrawer2D;

                                if (lines == null)
                                    continue;

                                foreach (LineDrawer2D.Line line in lines.Lines)
                                {
                                    Session.EventList el = lines.UserData.Value as Session.EventList;
                                    if (el != null && (float)Math.Abs(line.A.Position.X - mouseRelative) < threshold)
                                    {
                                        descriptionContainer = new Container();
                                        descriptionContainer.AnchorPoint.Value = new Vector2(0.5f, 1.0f);
                                        descriptionContainer.Position.Value = new Vector2(line.A.Position.X, 0.0f);
                                        descriptionContainer.Opacity.Value = 1.0f;
                                        descriptionContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                                        descriptionContainer.Add(new Binding<Vector2>(descriptionContainer.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
                                        timeline.Children.Add(descriptionContainer);
                                        TextElement description = new TextElement();
                                        description.WrapWidth.Value = 256;
                                        description.Text.Value = el.Name;
                                        description.FontFile.Value = "Font";
                                        descriptionContainer.Children.Add(description);
                                        stop = true;
                                        break;
                                    }
                                }
                                if (stop)
                                    break;
                            }
                        }
                    }

                    if (analyticsPlaying && !setTimelinePosition)
                    {
                        if (analyticsActiveSessions.Count == 0)
                            analyticsPlaying.Value = false;
                        else
                            playbackLocation.Value += dt * playbackSpeed;
                    }
                }
            };
            timelineUpdate.EnabledInEditMode.Value = true;
            result.Add(timelineUpdate);

            // Save
            addCommand("Save", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.S }, () => !editor.MovementEnabled, editor.Save);

            // Deselect all entities
            addCommand("Deselect all", new PCInput.Chord { Modifier = Keys.LeftControl, Key = Keys.A }, () => !editor.MovementEnabled, new Command
            {
                Action = delegate()
                {
                    editor.SelectedEntities.Clear();
                }
            });

            int brush = 1;
            Action<int> changeBrush = delegate(int delta)
            {
                int foundIndex = WorldFactory.StateList.FindIndex(x => x.Name == editor.Brush);
                if (foundIndex != -1)
                    brush = foundIndex;
                int stateCount = WorldFactory.States.Count + 1;
                brush = 1 + ((brush - 1 + delta) % (stateCount - 1));
                if (brush < 1)
                    brush = stateCount + ((brush - 1) % stateCount);
                if (brush == stateCount - 1)
                    editor.Brush.Value = "[Procedural]";
                else
                    editor.Brush.Value = WorldFactory.StateList[brush].Name;
            };
            result.Add(new CommandBinding(input.GetKeyDown(Keys.Q), () => editor.MapEditMode, delegate()
            {
                changeBrush(-1);
            }));
            result.Add(new CommandBinding(input.GetKeyDown(Keys.E), () => editor.MapEditMode && !input.GetKey(Keys.LeftShift), delegate()
            {
                changeBrush(1);
            }));
            result.Add(new CommandBinding<int>(input.MouseScrolled, () => editor.MapEditMode && !input.GetKey(Keys.LeftAlt), delegate(int delta)
            {
                editor.BrushSize.Value = Math.Max(1, editor.BrushSize.Value + delta);
            }));

            addCommand("Propagate current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.E }, () => editor.MapEditMode, editor.PropagateMaterial);
            addCommand("Sample current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.Q }, () => editor.MapEditMode, editor.SampleMaterial);
            addCommand("Delete current material", new PCInput.Chord { Modifier = Keys.LeftShift, Key = Keys.X }, () => editor.MapEditMode, editor.DeleteMaterial);

            editor.Add(new Binding<Vector2>(editor.Mouse, input.Mouse, () => !input.EnableLook));

            Camera camera = main.Camera;

            Property<float> cameraDistance = new Property<float> { Value = 10.0f };
            scroller.Add(new Binding<bool>(scroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
            input.Add(new CommandBinding<int>(input.MouseScrolled, () => input.GetKey(Keys.LeftAlt), delegate(int delta)
            {
                if (timelineScroller.Highlighted && !editor.MapEditMode)
                {
                    float newScale = Math.Max(timelines.Scale.Value.X + delta * 6.0f, timelineScroller.Size.Value.X / timelines.Size.Value.X);
                    Matrix absoluteTransform = timelines.GetAbsoluteTransform();
                    float x = input.Mouse.Value.X + ((absoluteTransform.Translation.X - input.Mouse.Value.X) * (newScale / timelines.Scale.Value.X));
                    timelines.Position.Value = new Vector2(x, 0.0f);
                    timelines.Scale.Value = new Vector2(newScale, 1.0f);
                }
                else
                    cameraDistance.Value = Math.Max(5, cameraDistance.Value + delta * -2.0f);
            }));
            input.Add(new Binding<bool>(input.EnableLook, () => editor.MapEditMode || (input.MiddleMouseButton && editor.TransformMode.Value == Editor.TransformModes.None), input.MiddleMouseButton, editor.MapEditMode, editor.TransformMode));
            input.Add(new Binding<Vector3, Vector2>(camera.Angles, x => new Vector3(-x.Y, x.X, 0.0f), input.Mouse, () => input.EnableLook));
            input.Add(new Binding<bool>(main.IsMouseVisible, x => !x, input.EnableLook));
            editor.Add(new Binding<Vector3>(camera.Position, () => editor.Position.Value - (camera.Forward.Value * cameraDistance), editor.Position, input.Mouse, cameraDistance));

            PointLight editorLight = result.GetOrCreate<PointLight>("EditorLight");
            editorLight.Serialize = false;
            editorLight.Editable = false;
            editorLight.Shadowed.Value = false;
            editorLight.Add(new Binding<float>(editorLight.Attenuation, x => x * 2.0f, cameraDistance));
            editorLight.Color.Value = Vector3.One;
            editorLight.Add(new Binding<Vector3>(editorLight.Position, main.Camera.Position));
            editorLight.Enabled.Value = false;

            ui.PopupCommands.Add(new EditorUI.PopupCommand
            {
                Description = "Toggle editor light",
                Enabled = () => editor.SelectedEntities.Count == 0 && !editor.MapEditMode,
                Action = new Command { Action = () => editorLight.Enabled.Value = !editorLight.Enabled },
            });

            editor.Add(new CommandBinding(input.RightMouseButtonDown, () => !ui.PopupVisible && !editor.MapEditMode && !input.EnableLook && editor.TransformMode.Value == Editor.TransformModes.None, delegate()
            {
                // We're not editing a map
                // And we're not transforming entities
                // So we must be selecting / deselecting entities
                bool multiselect = input.GetKey(Keys.LeftShift);

                Vector2 mouse = input.Mouse;
                Microsoft.Xna.Framework.Graphics.Viewport viewport = main.GraphicsDevice.Viewport;
                Vector3 ray = Vector3.Normalize(viewport.Unproject(new Vector3(mouse.X, mouse.Y, 1), camera.Projection, camera.View, Matrix.Identity) - viewport.Unproject(new Vector3(mouse.X, mouse.Y, 0), camera.Projection, camera.View, Matrix.Identity));

                Entity closestEntity;
                Transform closestTransform;
                this.raycast(main, ray, out closestEntity, out closestTransform);

                if (closestEntity != null)
                {
                    if (editor.SelectedEntities.Count == 1 && input.GetKey(Keys.LeftControl).Value)
                    {
                        // The user is trying to connect the two entities
                        Entity entity = editor.SelectedEntities.First();
                        Command<Entity> toggleConnection = entity.GetCommand<Entity>("ToggleEntityConnected");
                        if (toggleConnection != null)
                        {
                            toggleConnection.Execute(closestEntity);
                            editor.NeedsSave.Value = true;
                        }
                        return;
                    }

                    if (multiselect)
                    {
                        if (editor.SelectedEntities.Contains(closestEntity))
                            editor.SelectedEntities.Remove(closestEntity);
                        else
                            editor.SelectedEntities.Add(closestEntity);
                    }
                    else
                    {
                        editor.SelectedEntities.Clear();
                        editor.SelectedEntities.Add(closestEntity);
                        editor.SelectedTransform.Value = closestTransform;
                    }
                }
                else
                {
                    editor.SelectedEntities.Clear();
                    editor.SelectedTransform.Value = null;
                }
            }));

            editor.Add(new CommandBinding(input.GetKeyDown(Keys.Escape), delegate()
            {
                if (editor.TransformMode.Value != Editor.TransformModes.None)
                    editor.RevertTransform.Execute();
                else if (editor.MapEditMode)
                    editor.MapEditMode.Value = false;
            }));

            addCommand("Toggle voxel edit", new PCInput.Chord { Key = Keys.Tab }, delegate()
            {
                if (editor.TransformMode.Value != Editor.TransformModes.None)
                    return false;

                if (editor.MapEditMode)
                    return true;
                else
                    return editor.SelectedEntities.Count == 1 && editor.SelectedEntities[0].Get<Map>() != null;
            },
            new Command
            {
                Action = delegate()
                {
                    editor.MapEditMode.Value = !editor.MapEditMode;
                }
            });

            addCommand
            (
                "Grab (move)",
                new PCInput.Chord { Key = Keys.G },
                () => editor.SelectedEntities.Count > 0 && !input.EnableLook && !editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartTranslation
            );
            addCommand
            (
                "Grab (move)",
                new PCInput.Chord { Key = Keys.G },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartVoxelTranslation
            );
            addCommand
            (
                "Voxel duplicate",
                new PCInput.Chord { Key = Keys.C },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelDuplicate
            );
            addCommand
            (
                "Voxel yank",
                new PCInput.Chord { Key = Keys.Y },
                () => editor.MapEditMode && editor.VoxelSelectionActive && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelCopy
            );
            addCommand
            (
                "Voxel paste",
                new PCInput.Chord { Key = Keys.P },
                () => editor.MapEditMode && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.VoxelPaste
            );
            addCommand
            (
                "Rotate",
                new PCInput.Chord { Key = Keys.R },
                () => editor.SelectedEntities.Count > 0 && !editor.MapEditMode && !input.EnableLook && editor.TransformMode.Value == Editor.TransformModes.None,
                editor.StartRotation
            );
            addCommand
            (
                "Lock X axis",
                new PCInput.Chord { Key = Keys.X },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.X }
            );
            addCommand
            (
                "Lock Y axis",
                new PCInput.Chord { Key = Keys.Y },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.Y }
            );
            addCommand
            (
                "Lock Z axis",
                new PCInput.Chord { Key = Keys.Z },
                () => !editor.MapEditMode && editor.TransformMode.Value != Editor.TransformModes.None,
                new Command { Action = () => editor.TransformAxis.Value = Editor.TransformAxes.Z }
            );

            editor.Add(new CommandBinding
            (
                input.LeftMouseButtonDown,
                () => editor.TransformMode.Value != Editor.TransformModes.None,
                editor.CommitTransform
            ));
            editor.Add(new CommandBinding
            (
                input.RightMouseButtonDown,
                () => editor.TransformMode.Value != Editor.TransformModes.None,
                editor.RevertTransform
            ));
        }
Example #15
0
		public static void Attach(Main main, Entity entity, Player player, AnimatedModel model, FPSInput input, Phone phone, Property<bool> enableWalking, Property<bool> phoneActive, Property<bool> noteActive)
		{
			UIRenderer phoneUi = entity.GetOrCreate<UIRenderer>("PhoneUI");
			model["Phone"].Speed = model["VRPhone"].Speed = model["Note"].Speed = model["VRNote"].Speed = 0.25f;

			const float phoneWidth = 200.0f;

			phoneUi.RenderTargetBackground.Value = Microsoft.Xna.Framework.Color.White;
			phoneUi.RenderTargetSize.Value = new Point((int)phoneWidth, (int)(phoneWidth * 2.0f));
			phoneUi.Serialize = false;
			phoneUi.Enabled.Value = false;
#if VR
			if (main.VR)
				phoneUi.Reticle.Tint.Value = new Color(0.0f, 0.0f, 0.0f);
#endif

			Model phoneModel = entity.GetOrCreate<Model>("PhoneModel");
			phoneModel.Filename.Value = "Models\\phone";
			phoneModel.Color.Value = new Vector3(0.13f, 0.13f, 0.13f);
			phoneModel.Serialize = false;
			phoneModel.Enabled.Value = false;

			Property<Matrix> phoneBone = model.GetBoneTransform("Phone");
			phoneModel.Add(new Binding<Matrix>(phoneModel.Transform, () => phoneBone.Value * model.Transform, phoneBone, model.Transform));

			Model screen = entity.GetOrCreate<Model>("Screen");
			screen.Filename.Value = "Models\\plane";
			screen.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(screen.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), phoneUi.RenderTarget));
			screen.Add(new Binding<Matrix>(screen.Transform, x => Matrix.CreateTranslation(0.015f, 0.0f, 0.0f) * x, phoneModel.Transform));
			screen.Serialize = false;
			screen.Enabled.Value = false;

			PointLight phoneLight = entity.Create<PointLight>();
			phoneLight.Serialize = false;
			phoneLight.Enabled.Value = false;
			phoneLight.Attenuation.Value = 0.5f;
			phoneLight.Add(new Binding<Vector3, Matrix>(phoneLight.Position, x => x.Translation, screen.Transform));

			PointLight noteLight = entity.Create<PointLight>();
			noteLight.Serialize = false;
			noteLight.Enabled.Value = false;
			noteLight.Attenuation.Value = 1.0f;
			noteLight.Color.Value = new Vector3(0.3f);
			noteLight.Add(new Binding<Vector3>(noteLight.Position, () => Vector3.Transform(new Vector3(0.25f, 0.0f, 0.0f), phoneBone.Value * model.Transform), phoneBone, model.Transform));

			const float screenScale = 0.0007f;
			screen.Scale.Value = new Vector3(1.0f, (float)phoneUi.RenderTargetSize.Value.Y * screenScale, (float)phoneUi.RenderTargetSize.Value.X * screenScale);

			// Transform screen space mouse position into 3D, then back into the 2D space of the phone UI
			Property<Matrix> screenTransform = new Property<Matrix>();
			screen.Add(new Binding<Matrix>(screenTransform, () => Matrix.CreateScale(screen.Scale) * screen.Transform, screen.Scale, screen.Transform));
			phoneUi.Setup3D(screenTransform);

			// Phone UI

			const float padding = 8.0f;
			const float messageWidth = phoneWidth - padding * 2.0f;

			Func<Property<Color>, string, float, Container> makeButton = delegate(Property<Color> color, string text, float width)
			{
				Container bg = new Container();
				bg.Tint.Value = color;
				bg.PaddingBottom.Value = bg.PaddingLeft.Value = bg.PaddingRight.Value = bg.PaddingTop.Value = padding * 0.5f;
				bg.Add(new Binding<Color>(bg.Tint, () => bg.Highlighted ? new Color(color.Value.ToVector4() + new Vector4(0.2f, 0.2f, 0.2f, 0.0f)) : color, bg.Highlighted, color));

				TextElement msg = new TextElement();
				msg.Name.Value = "Text";
				msg.FontFile.Value = main.Font;
				msg.Text.Value = text;
				msg.WrapWidth.Value = width;
				bg.Children.Add(msg);
				return bg;
			};

			Action<Container, float> centerButton = delegate(Container button, float width)
			{
				TextElement text = (TextElement)button.Children[0];
				text.AnchorPoint.Value = new Vector2(0.5f, 0);
				text.Add(new Binding<Vector2>(text.Position, x => new Vector2(x.X * 0.5f, padding), button.Size));
				button.ResizeHorizontal.Value = false;
				button.ResizeVertical.Value = false;
				button.Size.Value = new Vector2(width, 36.0f * main.FontMultiplier);
			};

			Func<UIComponent, bool, Container> makeAlign = delegate(UIComponent component, bool right)
			{
				Container container = new Container();
				container.Opacity.Value = 0.0f;
				container.PaddingBottom.Value = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 0.0f;
				container.ResizeHorizontal.Value = false;
				container.Size.Value = new Vector2(messageWidth, 0.0f);
				component.AnchorPoint.Value = new Vector2(right ? 1.0f : 0.0f, 0.0f);
				component.Position.Value = new Vector2(right ? messageWidth : 0.0f, 0.0f);
				container.Children.Add(component);
				return container;
			};

			Property<Color> incomingColor = new Property<Color> { Value = new Color(0.0f, 0.0f, 0.0f, 1.0f) };
			Property<Color> outgoingColor = new Property<Color> { Value = new Color(0.0f, 0.175f, 0.35f, 1.0f) };
			Property<Color> alternateSenderColor = new Property<Color> { Value = new Color(0.25f, 0.0f, 0.25f, 1.0f) };
			Property<Color> composeColor = new Property<Color> { Value = new Color(0.5f, 0.0f, 0.0f, 1.0f) };
			Property<Color> disabledColor = new Property<Color> { Value = new Color(0.35f, 0.35f, 0.35f, 1.0f) };
			Property<Color> topBarColor = new Property<Color> { Value = new Color(0.15f, 0.15f, 0.15f, 1.0f) };

			Container topBarContainer = new Container();
			topBarContainer.ResizeHorizontal.Value = false;
			topBarContainer.Size.Value = new Vector2(phoneUi.RenderTargetSize.Value.X, 0.0f);
			topBarContainer.Tint.Value = topBarColor;
			phoneUi.Root.Children.Add(topBarContainer);

			ListContainer phoneTopBar = new ListContainer();
			phoneTopBar.Orientation.Value = ListContainer.ListOrientation.Horizontal;
			phoneTopBar.Spacing.Value = padding;
			topBarContainer.Children.Add(phoneTopBar);

			Sprite signalIcon = new Sprite();
			signalIcon.Image.Value = "Images\\signal";
			phoneTopBar.Children.Add(signalIcon);

			TextElement noService = new TextElement();
			noService.FontFile.Value = main.Font;
			noService.Text.Value = "\\no service";
			phoneTopBar.Children.Add(noService);

			signalIcon.Add(new Binding<bool>(signalIcon.Visible, () => player.SignalTower.Value.Target != null || phone.ActiveAnswers.Length > 0 || phone.Schedules.Length > 0, player.SignalTower, phone.ActiveAnswers.Length, phone.Schedules.Length));
			noService.Add(new Binding<bool>(noService.Visible, x => !x, signalIcon.Visible));

			ListContainer tabs = new ListContainer();
			tabs.Orientation.Value = ListContainer.ListOrientation.Horizontal;
			tabs.Spacing.Value = 0;
			phoneUi.Root.Children.Add(tabs);

			Property<Color> messageTabColor = new Property<Color> { Value = outgoingColor };
			phoneUi.Add(new Binding<Color, Phone.Mode>(messageTabColor, x => x == Phone.Mode.Messages ? outgoingColor : topBarColor, phone.CurrentMode));
			Container messageTab = makeButton(messageTabColor, "\\messages", phoneUi.RenderTargetSize.Value.X * 0.5f - padding);
			centerButton(messageTab, phoneUi.RenderTargetSize.Value.X * 0.5f);
			tabs.Children.Add(messageTab);
			messageTab.Add(new CommandBinding(messageTab.MouseLeftUp, delegate()
			{
				phone.CurrentMode.Value = Phone.Mode.Messages;
			}));

			Property<Color> photoTabColor = new Property<Color> { Value = topBarColor };
			phoneUi.Add(new Binding<Color>(photoTabColor, delegate()
			{
				if (phone.CurrentMode == Phone.Mode.Photos)
					return outgoingColor;
				else if (string.IsNullOrEmpty(phone.Photo))
					return disabledColor;
				else
					return topBarColor;
			}, phone.CurrentMode, phone.Photo));
			Container photoTab = makeButton(photoTabColor, "\\photos", phoneUi.RenderTargetSize.Value.X * 0.5f - padding);
			centerButton(photoTab, phoneUi.RenderTargetSize.Value.X * 0.5f);
			tabs.Children.Add(photoTab);
			photoTab.Add(new CommandBinding(photoTab.MouseLeftUp, delegate()
			{
				if (!string.IsNullOrEmpty(phone.Photo))
					phone.CurrentMode.Value = Phone.Mode.Photos;
			}));

			tabs.Add(new Binding<Vector2>(tabs.Position, x => new Vector2(0, x.Y), topBarContainer.Size));

			ListContainer messageLayout = new ListContainer();
			messageLayout.Spacing.Value = padding;
			messageLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
			messageLayout.Add(new Binding<Vector2>(messageLayout.Position, () => new Vector2(padding, topBarContainer.Size.Value.Y + tabs.Size.Value.Y), topBarContainer.Size, tabs.Size));
			messageLayout.Add(new Binding<Vector2>(messageLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X - padding * 2.0f, phoneUi.RenderTargetSize.Value.Y - padding - topBarContainer.Size.Value.Y - tabs.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size, tabs.Size));
			messageLayout.Add(new Binding<bool, Phone.Mode>(messageLayout.Visible, x => x == Phone.Mode.Messages, phone.CurrentMode));
			phoneUi.Root.Children.Add(messageLayout);

			Container photoLayout = new Container();
			photoLayout.Opacity.Value = 0;
			photoLayout.PaddingLeft.Value = photoLayout.PaddingRight.Value = photoLayout.PaddingTop.Value = photoLayout.PaddingBottom.Value = 0;
			photoLayout.Add(new Binding<Vector2>(photoLayout.Position, () => new Vector2(0, topBarContainer.Size.Value.Y + tabs.Size.Value.Y), topBarContainer.Size, tabs.Size));
			photoLayout.Add(new Binding<Vector2>(photoLayout.Size, () => new Vector2(phoneUi.RenderTargetSize.Value.X, phoneUi.RenderTargetSize.Value.Y - topBarContainer.Size.Value.Y - tabs.Size.Value.Y), phoneUi.RenderTargetSize, topBarContainer.Size, tabs.Size));
			photoLayout.Add(new Binding<bool>(photoLayout.Visible, x => !x, messageLayout.Visible));
			phoneUi.Root.Children.Add(photoLayout);

			Sprite photoImage = new Sprite();
			photoImage.AnchorPoint.Value = new Vector2(0.5f, 0.5f);
			photoImage.Add(new Binding<string>(photoImage.Image, phone.Photo));
			photoImage.Add(new Binding<Vector2>(photoImage.Position, x => x * 0.5f, photoLayout.Size));
			photoLayout.Children.Add(photoImage);

			Container composeButton = makeButton(composeColor, "\\compose", messageWidth - padding * 2.0f);
			TextElement composeText = (TextElement)composeButton.GetChildByName("Text");
			composeText.Add(new Binding<string, bool>(composeText.Text, x => x ? "\\compose gamepad" : "\\compose", main.GamePadConnected));
			UIComponent composeAlign = makeAlign(composeButton, true);

			Scroller phoneScroll = new Scroller();
			phoneScroll.ResizeVertical.Value = false;
			phoneScroll.Add(new Binding<Vector2>(phoneScroll.Size, () => new Vector2(messageLayout.Size.Value.X, messageLayout.Size.Value.Y - messageLayout.Spacing.Value - composeAlign.ScaledSize.Value.Y), messageLayout.Size, messageLayout.Spacing, composeAlign.ScaledSize));

			messageLayout.Children.Add(phoneScroll);
			messageLayout.Children.Add(composeAlign);

			ListContainer msgList = new ListContainer();
			msgList.Spacing.Value = padding * 0.5f;
			msgList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			msgList.ResizePerpendicular.Value = false;
			msgList.Size.Value = new Vector2(messageWidth, 0.0f);
			phoneScroll.Children.Add(msgList);

			Container answerContainer = new Container();
			answerContainer.PaddingBottom.Value = answerContainer.PaddingLeft.Value = answerContainer.PaddingRight.Value = answerContainer.PaddingTop.Value = padding;
			answerContainer.Tint.Value = incomingColor;
			answerContainer.AnchorPoint.Value = new Vector2(1.0f, 1.0f);
			phoneUi.Root.CheckLayout();
			answerContainer.Position.Value = composeAlign.GetAbsolutePosition() + new Vector2(composeAlign.ScaledSize.Value.X, 0);
			phoneUi.Root.Children.Add(answerContainer);
			answerContainer.Visible.Value = false;

			ListContainer answerList = new ListContainer();
			answerList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			answerList.Alignment.Value = ListContainer.ListAlignment.Max;
			answerContainer.Children.Add(answerList);

			int selectedAnswer = 0;

			composeButton.Add(new CommandBinding(composeButton.MouseLeftUp, delegate()
			{
				answerContainer.Visible.Value = !answerContainer.Visible;
				if (answerContainer.Visible && main.GamePadConnected)
				{
					selectedAnswer = 0;
					foreach (UIComponent answer in answerList.Children)
						answer.Highlighted.Value = false;
					answerList.Children[0].Highlighted.Value = true;
				}
			}));

			tabs.Add(new Binding<bool>(tabs.EnableInput, () => !main.Paused && !answerContainer.Visible, answerContainer.Visible, main.Paused));
			msgList.Add(new Binding<bool>(msgList.EnableInput, () => !main.Paused && !answerContainer.Visible, answerContainer.Visible, main.Paused));
			answerContainer.Add(new Binding<bool>(answerContainer.EnableInput, x => !x, main.Paused));
			composeButton.Add(new Binding<bool>(composeButton.EnableInput, x => !x, main.Paused));

			Action scrollToBottom = delegate()
			{
				// HACK
				Animation scroll = new Animation
				(
					new Animation.Delay(0.01f),
					new Animation.Execute(delegate()
					{
						phoneScroll.ScrollToBottom();
					})
				);
				entity.Add(scroll);
			};

			// Note

			UIRenderer noteUi = entity.GetOrCreate<UIRenderer>("NoteUI");

			const float noteWidth = 400.0f;

			noteUi.RenderTargetBackground.Value = new Microsoft.Xna.Framework.Color(0.8f, 0.75f, 0.7f);
			noteUi.RenderTargetSize.Value = new Point((int)noteWidth, (int)(noteWidth * 1.29f)); // 8.5x11 aspect ratio
			noteUi.Serialize = false;
			noteUi.Enabled.Value = false;

			Model noteModel = entity.GetOrCreate<Model>("Note");
			noteModel.Filename.Value = "Models\\note";
			noteModel.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(noteModel.GetRenderTarget2DParameter("Diffuse" + Model.SamplerPostfix), noteUi.RenderTarget));
			noteModel.Add(new Binding<Matrix>(noteModel.Transform, x => Matrix.CreateTranslation(-0.005f, 0.05f, 0.08f) * x, phoneModel.Transform));
			noteModel.Serialize = false;
			noteModel.Enabled.Value = false;

			Container togglePhoneMessage = null;

			entity.Add(new NotifyBinding(delegate()
			{
				bool hasSignalTower = (player.SignalTower.Value.Target != null && player.SignalTower.Value.Target.Active && !string.IsNullOrEmpty(player.SignalTower.Value.Target.Get<SignalTower>().Initial));
				if (hasSignalTower)
					phone.Enabled.Value = true;

				bool hasNoteOrSignalTower = (player.Note.Value.Target != null && player.Note.Value.Target.Active) || hasSignalTower;

				if (togglePhoneMessage == null && hasNoteOrSignalTower)
					togglePhoneMessage = main.Menu.ShowMessage(entity, hasSignalTower ? "\\signal tower prompt" : "\\note prompt");
				else if (togglePhoneMessage != null && !hasNoteOrSignalTower && !phoneActive && !noteActive)
				{
					main.Menu.HideMessage(null, togglePhoneMessage);
					togglePhoneMessage = null;
				}
			}, player.Note, player.SignalTower));

			entity.Add(new CommandBinding(entity.Delete, delegate()
			{
				if (togglePhoneMessage != null && togglePhoneMessage.Active)
					togglePhoneMessage.Delete.Execute();
				if (noteActive)
				{
					noteActive.Value = false;
					player.Note.Value = null;
					enableWalking.Value = true;
				}
			}));

			// Note UI

			const float notePadding = 40.0f;

			ListContainer noteLayout = new ListContainer();
			noteLayout.Spacing.Value = padding;
			noteLayout.Orientation.Value = ListContainer.ListOrientation.Vertical;
			noteLayout.Alignment.Value = ListContainer.ListAlignment.Min;
			noteLayout.Position.Value = new Vector2(notePadding, notePadding);
			noteLayout.Add(new Binding<Vector2, Point>(noteLayout.Size, x => new Vector2(x.X - notePadding * 2.0f, x.Y - notePadding * 2.0f), noteUi.RenderTargetSize));
			noteUi.Root.Children.Add(noteLayout);

			Sprite noteUiImage = new Sprite();
			noteLayout.Children.Add(noteUiImage);

			TextElement noteUiText = new TextElement();
			noteUiText.FontFile.Value = main.Font;
			noteUiText.Tint.Value = new Microsoft.Xna.Framework.Color(0.1f, 0.1f, 0.1f);
			noteUiText.Add(new Binding<float, Vector2>(noteUiText.WrapWidth, x => x.X, noteLayout.Size));
			noteLayout.Children.Add(noteUiText);

			// Toggle note
			Animation noteAnim = null;

			float startRotationY = 0;
			Action<bool> showNote = delegate(bool show)
			{
				model.Stop("Phone", "Note", "VRPhone", "VRNote");
				Entity noteEntity = player.Note.Value.Target;
				noteActive.Value = show && noteEntity != null;
				Note note = noteEntity != null ? noteEntity.Get<Note>() : null;
				if (noteActive)
				{
					input.EnableLook.Value = input.EnableMouse.Value = false;
					enableWalking.Value = false;
					noteModel.Enabled.Value = true;
					noteUi.Enabled.Value = true;
					noteLight.Enabled.Value = true;
					Session.Recorder.Event(main, "Note", note.Text);
					noteUiImage.Image.Value = note.Image;
					noteUiText.Text.Value = note.Text;
					string noteAnimation;
#if VR
					if (main.VR)
						noteAnimation = "VRNote";
					else
#endif
						noteAnimation = "Note";

					model.StartClip(noteAnimation, 6, true, AnimatedModel.DefaultBlendTime * 2.0f);
					AkSoundEngine.PostEvent(AK.EVENTS.PLAY_NOTE_PICKUP, entity);

					if (noteAnim != null && noteAnim.Active)
						noteAnim.Delete.Execute();
					else
						startRotationY = input.Mouse.Value.Y;
					// Level the player's view
					noteAnim = new Animation
					(
						new Animation.Ease
						(
							new Animation.Custom(delegate(float x)
							{
								input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
							}, 0.5f),
							Animation.Ease.EaseType.OutQuadratic
						)
					);
					entity.Add(noteAnim);
				}
				else
				{
					enableWalking.Value = true;
					if (note != null)
						Session.Recorder.Event(main, "NoteEnd");
					AkSoundEngine.PostEvent(AK.EVENTS.PLAY_NOTE_DROP, entity);
					if (note != null && !note.IsCollected)
						note.IsCollected.Value = true;

					// Return the player's view
					if (noteAnim != null && noteAnim.Active)
						noteAnim.Delete.Execute();
					noteAnim = new Animation
					(
						new Animation.Ease
						(
							new Animation.Custom(delegate(float x)
							{
								input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * x);
							}, 0.5f),
							Animation.Ease.EaseType.OutQuadratic
						),
						new Animation.Execute(delegate()
						{
							noteModel.Enabled.Value = false;
							noteUi.Enabled.Value = false;
							noteLight.Enabled.Value = false;
							input.EnableLook.Value = input.EnableMouse.Value = true;
						})
					);
					entity.Add(noteAnim);
				}
			};

			// Toggle phone

			Animation phoneAnim = null;

			Action<bool> showPhone = delegate(bool show)
			{
				if (togglePhoneMessage != null)
				{
					main.Menu.HideMessage(null, togglePhoneMessage);
					togglePhoneMessage = null;
				}

				if (show || (phone.Schedules.Length == 0 && !phone.WaitForAnswer))
				{
					phoneActive.Value = show;
					answerContainer.Visible.Value = false;

					model.Stop("Phone", "Note", "VRPhone", "VRNote");
					if (phoneActive)
					{
						phoneUi.IsMouseVisible.Value = true;
						enableWalking.Value = false;
						phoneModel.Enabled.Value = true;
						screen.Enabled.Value = true;
						phoneUi.Enabled.Value = true;
						phoneLight.Enabled.Value = true;
						input.EnableLook.Value = input.EnableMouse.Value = false;
						Session.Recorder.Event(main, "Phone");
						phoneScroll.CheckLayout();
						scrollToBottom();

						string phoneAnimation;
#if VR
						if (main.VR)
							phoneAnimation = "VRPhone";
						else
#endif
							phoneAnimation = "Phone";

						model.StartClip(phoneAnimation, 6, true, AnimatedModel.DefaultBlendTime * 2.0f);

						// Level the player's view
						if (phoneAnim != null && phoneAnim.Active)
							phoneAnim.Delete.Execute();
						else
							startRotationY = input.Mouse.Value.Y;
						phoneAnim = new Animation
						(
							new Animation.Ease
							(
								new Animation.Custom(delegate(float x)
								{
									input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * (1.0f - x));
								}, 0.5f),
								Animation.Ease.EaseType.OutQuadratic
							)
						);
						entity.Add(phoneAnim);
					}
					else
					{
						Session.Recorder.Event(main, "PhoneEnd");
						enableWalking.Value = true;
						phoneUi.IsMouseVisible.Value = false;

						// Return the player's view
						if (phoneAnim != null && phoneAnim.Active)
							phoneAnim.Delete.Execute();
						phoneAnim = new Animation
						(
							new Animation.Ease
							(
								new Animation.Custom(delegate(float x)
								{
									input.Mouse.Value = new Vector2(input.Mouse.Value.X, startRotationY * x);
								}, 0.5f),
								Animation.Ease.EaseType.OutQuadratic
							),
							new Animation.Execute(delegate()
							{
								phoneModel.Enabled.Value = false;
								screen.Enabled.Value = false;
								phoneUi.Enabled.Value = false;
								phoneLight.Enabled.Value = false;
								input.EnableLook.Value = input.EnableMouse.Value = true;
							})
						);
						entity.Add(phoneAnim);
					}
				}
			};

			input.Bind(main.Settings.TogglePhone, PCInput.InputState.Down, delegate()
			{
				// Special hack to prevent phone toggling when you're trying to open the Steam overlay
				if (main.Settings.TogglePhone.Value.Key == Keys.Tab && input.GetKey(Keys.LeftShift))
					return;

				if (noteActive || phoneActive || phone.CanReceiveMessages)
				{
					if (!phoneActive && (noteActive || player.Note.Value.Target != null))
						showNote(!noteActive);
					else if (phone.Enabled)
						showPhone(!phoneActive);
				}
			});

			phone.Add(new CommandBinding(phone.Show, delegate()
			{
				phone.Enabled.Value = true;
				if (!phoneActive)
					showPhone(true);
			}));

			// Gamepad code for the phone

			input.Add(new CommandBinding(input.GetButtonUp(Buttons.A), () => phoneActive && composeButton.Visible && phone.CurrentMode.Value == Phone.Mode.Messages, delegate()
			{
				if (answerContainer.Visible)
					answerList.Children[selectedAnswer].MouseLeftUp.Execute();
				else
					composeButton.MouseLeftUp.Execute();
			}));

			input.Add(new CommandBinding(input.GetButtonUp(Buttons.B), () => phoneActive && answerContainer.Visible, delegate()
			{
				answerContainer.Visible.Value = false;
			}));

			const float moveInterval = 0.1f;
			const float switchInterval = 0.2f;
			float lastScroll = 0;
			float lastModeSwitch = 0;
			Action<int> scrollPhone = delegate(int delta)
			{
				if (main.TotalTime - lastScroll > moveInterval
					&& main.TotalTime - lastModeSwitch > switchInterval)
				{
					if (answerContainer.Visible)
					{
						answerList.Children[selectedAnswer].Highlighted.Value = false;
						selectedAnswer += delta;
						while (selectedAnswer < 0)
							selectedAnswer += answerList.Children.Length;
						while (selectedAnswer > answerList.Children.Length - 1)
							selectedAnswer -= answerList.Children.Length;
						answerList.Children[selectedAnswer].Highlighted.Value = true;
					}
					else
						phoneScroll.MouseScrolled.Execute(delta * -4);
					lastScroll = main.TotalTime;
				}
			};

			Action switchMode = delegate()
			{
				if (main.TotalTime - lastScroll > switchInterval
					&& main.TotalTime - lastModeSwitch > moveInterval)
				{
					Phone.Mode current = phone.CurrentMode;
					Phone.Mode nextMode = current == Phone.Mode.Messages ? Phone.Mode.Photos : Phone.Mode.Messages;
					if (nextMode == Phone.Mode.Photos && string.IsNullOrEmpty(phone.Photo))
						nextMode = Phone.Mode.Messages;
					phone.CurrentMode.Value = nextMode;
					lastModeSwitch = main.TotalTime;
				}
			};
			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickLeft), () => phoneActive && !answerContainer.Visible, switchMode));
			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickRight), () => phoneActive && !answerContainer.Visible, switchMode));
			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadLeft), () => phoneActive && !answerContainer.Visible, switchMode));
			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadRight), () => phoneActive && !answerContainer.Visible, switchMode));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickUp), () => phoneActive, delegate()
			{
				scrollPhone(-1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadUp), () => phoneActive, delegate()
			{
				scrollPhone(-1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickDown), () => phoneActive, delegate()
			{
				scrollPhone(1);
			}));

			input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadDown), () => phoneActive, delegate()
			{
				scrollPhone(1);
			}));

			Func<Phone.Sender, Property<Color>> messageColor = delegate(Phone.Sender sender)
			{
				switch (sender)
				{
					case Phone.Sender.Player:
						return outgoingColor;
					case Phone.Sender.A:
						return incomingColor;
					default:
						return alternateSenderColor;
				}
			};

			msgList.Add(new ListBinding<UIComponent, Phone.Message>
			(
				msgList.Children,
				phone.Messages,
				delegate(Phone.Message msg)
				{
					return makeAlign(makeButton(messageColor(msg.Sender), "\\" + msg.Name, messageWidth - padding * 2.0f), msg.Sender == Phone.Sender.Player);
				}
			));

			Action<float, Container> animateMessage = delegate(float delay, Container msg)
			{
				msg.CheckLayout();
				Vector2 originalSize = msg.Size;
				msg.Size.Value = new Vector2(0, originalSize.Y);
				entity.Add(new Animation
				(
					new Animation.Delay(delay),
					new Animation.Ease(new Animation.Vector2MoveTo(msg.Size, originalSize, 0.5f), Animation.Ease.EaseType.OutExponential)
				));
			};

			Container typingIndicator = null;

			Action showTypingIndicator = delegate()
			{
				typingIndicator = makeAlign(makeButton(incomingColor, "\\...", messageWidth - padding * 2.0f), false);
				msgList.Children.Add(typingIndicator);
				animateMessage(0.2f, typingIndicator);
			};

			if (phone.Schedules.Length > 0)
				showTypingIndicator();

			answerList.Add(new ListBinding<UIComponent, Phone.Ans>
			(
				answerList.Children,
				phone.ActiveAnswers,
				delegate(Phone.Ans answer)
				{
					UIComponent button = makeButton(outgoingColor, "\\" + answer.Name, messageWidth - padding * 4.0f);
					button.Add(new CommandBinding(button.MouseLeftUp, delegate()
					{
						if (!phone.WaitForAnswer) // If we're not waiting for an answer, the player must be initiating a conversation
						{
							// This is the start of a conversation
							// Disable the signal tower if we're in range
							Entity s = player.SignalTower.Value.Target;
							if (s != null)
								s.Get<SignalTower>().Initial.Value = null;
						}

						AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PHONE_SEND, entity);
						phone.Answer(answer);

						scrollToBottom();
						if (phone.Schedules.Length == 0) // No more messages incoming
						{
							if (togglePhoneMessage == null)
								togglePhoneMessage = main.Menu.ShowMessage(entity, "\\phone done prompt");
						}
						else
						{
							// More messages incoming
							showTypingIndicator();
						}
					}));
					return button;
				}
			));

			Action refreshComposeButtonVisibility = delegate()
			{
				bool show = phone.ActiveAnswers.Length > 0 && phone.Schedules.Length == 0;
				answerContainer.Visible.Value &= show;
				composeButton.Visible.Value = show;
				selectedAnswer = 0;
			};
			composeButton.Add(new ListNotifyBinding<Phone.Ans>(refreshComposeButtonVisibility, phone.ActiveAnswers));
			composeButton.Add(new ListNotifyBinding<Phone.Schedule>(refreshComposeButtonVisibility, phone.Schedules));
			refreshComposeButtonVisibility();

			entity.Add(new CommandBinding(phone.MessageReceived, delegate()
			{
				if (typingIndicator != null)
				{
					typingIndicator.Delete.Execute();
					typingIndicator = null;
				}
				
				if (phone.Schedules.Length > 0)
					showTypingIndicator();

				float delay;
				if (phoneActive)
				{
					scrollToBottom();
					delay = 0;
				}
				else
				{
					showPhone(true);
					delay = 0.5f;
				}

				// Animate the new message
				animateMessage(delay, (Container)msgList.Children[msgList.Children.Length - 1].Children[0]);

				AkSoundEngine.PostEvent(AK.EVENTS.PLAY_PHONE_VIBRATE, entity);
				if (togglePhoneMessage == null && phone.Schedules.Length == 0 && phone.ActiveAnswers.Length == 0) // No more messages incoming, and no more answers to give
					togglePhoneMessage = main.Menu.ShowMessage(entity, "[{{TogglePhone}}]");
			}));

			if (noteActive)
				showNote(true);
			else if (phoneActive)
				showPhone(true);
		}
Example #16
0
        public override void Bind(Entity result, Main main, bool creating = false)
        {
            this.SetMain(result, main);
            Transform transform = result.Get<Transform>();
            PlayerTrigger trigger = result.Get<PlayerTrigger>();
            Property<string> nextMap = result.GetProperty<string>("NextMap");
            Property<string> startSpawnPoint = result.GetProperty<string>("SpawnPoint");

            trigger.Add(new TwoWayBinding<Vector3>(transform.Position, trigger.Position));
            trigger.Add(new CommandBinding<Entity>(trigger.PlayerEntered, delegate(Entity player)
            {
                XmlSerializer serializer = new XmlSerializer(typeof(List<Entity>));

                Container notification = new Container();
                notification.Tint.Value = Microsoft.Xna.Framework.Color.Black;
                notification.Opacity.Value = 0.5f;
                TextElement notificationText = new TextElement();
                notificationText.Name.Value = "Text";
                notificationText.FontFile.Value = "Font";
                notificationText.Text.Value = "Loading...";
                notification.Children.Add(notificationText);
                ((GameMain)main).UI.Root.GetChildByName("Notifications").Children.Add(notification);

                Stream stream = new MemoryStream();
                main.AddComponent(new Animation
                (
                    new Animation.Delay(0.01f),
                    new Animation.Execute(delegate()
                    {
                        // We are exiting the map; just save the state of the map without the player.
                        ListProperty<PlayerFactory.RespawnLocation> respawnLocations = Factory.Get<PlayerDataFactory>().Instance(main).GetOrMakeListProperty<PlayerFactory.RespawnLocation>("RespawnLocations");
                        respawnLocations.Clear();

                        List<Entity> persistentEntities = main.Entities.Where((Func<Entity, bool>)MapExitFactory.isPersistent).ToList();

                        serializer.Serialize(stream, persistentEntities);

                        foreach (Entity e in persistentEntities)
                            e.Delete.Execute();

                        ((GameMain)main).StartSpawnPoint = startSpawnPoint;
                    }),
                    new Animation.Execute(((GameMain)main).SaveCurrentMap),
                    new Animation.Set<string>(main.MapFile, nextMap),
                    new Animation.Execute(delegate()
                    {
                        notification.Visible.Value = false;
                        stream.Seek(0, SeekOrigin.Begin);
                        List<Entity> entities = (List<Entity>)serializer.Deserialize(stream);
                        foreach (Entity entity in entities)
                        {
                            Factory factory = Factory.Get(entity.Type);
                            factory.Bind(entity, main);
                            main.Add(entity);
                        }
                        stream.Dispose();
                    }),
                    new Animation.Delay(1.5f),
                    new Animation.Set<string>(notificationText.Text, "Saving..."),
                    new Animation.Set<bool>(notification.Visible, true),
                    new Animation.Delay(0.01f),
                    new Animation.Execute(((GameMain)main).Save),
                    new Animation.Set<string>(notificationText.Text, "Saved"),
                    new Animation.Parallel
                    (
                        new Animation.FloatMoveTo(notification.Opacity, 0.0f, 1.0f),
                        new Animation.FloatMoveTo(notificationText.Opacity, 0.0f, 1.0f)
                    ),
                    new Animation.Execute(notification.Delete)
                ));
            }));
        }
Example #17
0
        public override void Awake()
        {
            this.Serialize         = false;
            this.EnabledWhenPaused = false;

#if STEAMWORKS
            this.personaCallback = Callback <PersonaStateChange_t> .Create(this.onPersonaStateChange);
#endif

            {
                Container container = this.main.UIFactory.CreateContainer();
                container.Opacity.Value       = 0.5f;
                container.PaddingBottom.Value = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 16.0f * this.main.FontMultiplier;
                container.AnchorPoint.Value   = new Vector2(1.0f, 0.0f);
                container.Add(new Binding <Vector2, Point>(container.Position, x => new Vector2(x.X * 0.9f, x.Y * 0.1f), this.main.ScreenSize));
                container.Visible.Value = false;
                this.main.UI.Root.Children.Add(container);
                container.Add(new CommandBinding(this.Delete, container.Delete));
                container.Add(new CommandBinding(this.ShowEnd, container.Delete));
                container.Add(new CommandBinding(this.Show, delegate() { container.Visible.Value = true; }));

                ListContainer list = new ListContainer();
                list.Orientation.Value = ListContainer.ListOrientation.Vertical;
                list.Alignment.Value   = ListContainer.ListAlignment.Max;
                container.Children.Add(list);

                TextElement elapsedTime = new TextElement();
                elapsedTime.FontFile.Value = this.main.FontLarge;
                elapsedTime.Add(new Binding <string, float>(elapsedTime.Text, SecondsToTimeString, this.ElapsedTime));
                list.Children.Add(elapsedTime);

                TextElement bestTime = this.main.UIFactory.CreateLabel();
                bestTime.Add(new Binding <string, float>(bestTime.Text, SecondsToTimeString, this.BestTime));
                list.Children.Add(bestTime);
            }

            this.ShowEnd.Action = delegate()
            {
                if (this.shown)
                {
                    return;
                }
                this.shown = true;

                Container container = this.main.UIFactory.CreateContainer();
                container.Opacity.Value       = 0.5f;
                container.PaddingBottom.Value = container.PaddingLeft.Value = container.PaddingRight.Value = container.PaddingTop.Value = 16.0f * this.main.FontMultiplier;
                container.AnchorPoint.Value   = new Vector2(0.5f, 0.5f);
                container.Add(new Binding <Vector2, Point>(container.Position, x => new Vector2(x.X * 0.5f, x.Y * 0.5f), this.main.ScreenSize));
                this.main.UI.Root.Children.Add(container);
                container.Add(new CommandBinding(this.Delete, container.Delete));

                ListContainer list = new ListContainer();
                list.Orientation.Value = ListContainer.ListOrientation.Vertical;
                list.Alignment.Value   = ListContainer.ListAlignment.Middle;
                list.Spacing.Value     = this.spacing;
                container.Children.Add(list);

                TextElement elapsedTime = new TextElement();
                elapsedTime.FontFile.Value = this.main.FontLarge;
                elapsedTime.Add(new Binding <string, float>(elapsedTime.Text, SecondsToTimeString, this.ElapsedTime));
                list.Children.Add(elapsedTime);

                TextElement bestTime = this.main.UIFactory.CreateLabel();
                bestTime.Add(new Binding <string>(bestTime.Text, () => string.Format(main.Strings.Get("best time"), SecondsToTimeString(this.BestTime)), this.BestTime, main.Strings.Language));
                list.Children.Add(bestTime);

#if STEAMWORKS
                Container leaderboard = this.main.UIFactory.CreateContainer();
                this.resizeContainer(leaderboard);
                list.Children.Add(leaderboard);

                ListContainer leaderboardList = new ListContainer();
                leaderboardList.ResizePerpendicular.Value = false;
                leaderboardList.Size.Value        = new Vector2(this.width - 8.0f, 0);
                leaderboardList.Orientation.Value = ListContainer.ListOrientation.Vertical;
                leaderboardList.Alignment.Value   = ListContainer.ListAlignment.Middle;
                leaderboardList.Spacing.Value     = this.spacing;
                leaderboard.Children.Add(leaderboardList);

                this.LeaderboardSync.Action = delegate()
                {
                    leaderboardList.Children.Clear();
                    TextElement leaderboardLabel = this.main.UIFactory.CreateLabel();
                    leaderboardLabel.Text.Value = "\\leaderboard";
                    leaderboardList.Children.Add(leaderboardLabel);
                    TextElement loading = this.main.UIFactory.CreateLabel();
                    loading.Text.Value = "\\loading";
                    leaderboardList.Children.Add(loading);
                };

                this.OnLeaderboardSync.Action = delegate(LeaderboardScoresDownloaded_t globalScores, LeaderboardScoresDownloaded_t friendScores)
                {
                    leaderboardList.Children.Clear();
                    TextElement leaderboardLabel = this.main.UIFactory.CreateLabel();
                    leaderboardLabel.Text.Value = "\\leaderboard";
                    leaderboardList.Children.Add(leaderboardLabel);

                    int[] details = new int[] {};
                    for (int i = 0; i < globalScores.m_cEntryCount; i++)
                    {
                        LeaderboardEntry_t entry;
                        SteamUserStats.GetDownloadedLeaderboardEntry(globalScores.m_hSteamLeaderboardEntries, i, out entry, details, 0);
                        leaderboardList.Children.Add(this.leaderboardEntry(entry));
                    }

                    if (friendScores.m_cEntryCount > 1)
                    {
                        TextElement friendsLabel = this.main.UIFactory.CreateLabel();
                        friendsLabel.Text.Value = "\\friends";
                        leaderboardList.Children.Add(friendsLabel);

                        for (int i = 0; i < friendScores.m_cEntryCount; i++)
                        {
                            LeaderboardEntry_t entry;
                            SteamUserStats.GetDownloadedLeaderboardEntry(friendScores.m_hSteamLeaderboardEntries, i, out entry, details, 0);
                            if (entry.m_steamIDUser != SteamUser.GetSteamID())
                            {
                                leaderboardList.Children.Add(this.leaderboardEntry(entry));
                            }
                        }
                    }
                };

                this.OnLeaderboardError.Action = delegate()
                {
                    leaderboardList.Children.Clear();
                    TextElement error = this.main.UIFactory.CreateLabel();
                    error.Text.Value = "\\leaderboard error";
                    leaderboardList.Children.Add(error);
                };

                this.LeaderboardSync.Execute();
#endif

                Container retry = this.main.UIFactory.CreateButton("\\retry", delegate()
                {
                    this.Retry.Execute();
                });
                this.resizeButton(retry);
                list.Children.Add(retry);

                if (this.main.Settings.GodModeProperty || Path.GetDirectoryName(this.main.MapFile) == this.main.CustomMapDirectory)
                {
                    Container edit = this.main.UIFactory.CreateButton("\\edit mode", delegate()
                    {
                        this.Edit.Execute();
                    });
                    this.resizeButton(edit);
                    list.Children.Add(edit);
                }

                if (!string.IsNullOrEmpty(this.NextMap))
                {
                    Container next = this.main.UIFactory.CreateButton("\\next level", delegate()
                    {
                        this.LoadNextMap.Execute();
                    });
                    this.resizeButton(next);
                    list.Children.Add(next);
                }

                Container mainMenu = this.main.UIFactory.CreateButton("\\main menu", delegate()
                {
                    this.MainMenu.Execute();
                });
                this.resizeButton(mainMenu);
                list.Children.Add(mainMenu);

                this.main.UI.IsMouseVisible.Value = true;

                const float gamepadMoveInterval = 0.1f;
                float       lastGamepadMove     = 0.0f;

                Func <int, int, int> nextButton = delegate(int search, int dir)
                {
                    int i = search;
                    while (true)
                    {
                        i = i + dir;
                        if (i < 0)
                        {
                            i = list.Children.Count - 1;
                        }
                        else if (i >= list.Children.Count)
                        {
                            i = 0;
                        }
                        UIComponent item = list.Children[i];
                        if (item is Container)
                        {
                            return(i);
                        }
                    }
                };

                int selected = nextButton(0, 1);
                if (main.GamePadConnected)
                {
                    list.Children[selected].Highlighted.Value = true;
                }

                PCInput      input         = this.Entity.GetOrCreate <PCInput>();
                Action <int> moveSelection = delegate(int delta)
                {
                    if (this.main.GameTime.TotalGameTime.TotalSeconds - lastGamepadMove > gamepadMoveInterval)
                    {
                        Container button;
                        if (selected < list.Children.Length)
                        {
                            button = (Container)list.Children[selected];
                            button.Highlighted.Value = false;
                        }

                        selected = nextButton(selected, delta);

                        button = (Container)list.Children[selected];
                        button.Highlighted.Value = true;
                        lastGamepadMove          = (float)this.main.GameTime.TotalGameTime.TotalSeconds;
                    }
                };

                input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickUp), delegate()
                {
                    moveSelection(-1);
                }));

                input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadUp), delegate()
                {
                    moveSelection(-1);
                }));

                input.Add(new CommandBinding(input.GetButtonDown(Buttons.LeftThumbstickDown), delegate()
                {
                    moveSelection(1);
                }));

                input.Add(new CommandBinding(input.GetButtonDown(Buttons.DPadDown), delegate()
                {
                    moveSelection(1);
                }));

                input.Add(new CommandBinding(input.GetButtonDown(Buttons.A), delegate()
                {
                    if (selected < list.Children.Count)
                    {
                        UIComponent selectedItem = list.Children[selected];
                        selectedItem.MouseLeftUp.Execute();
                    }
                }));
            };
        }
Example #18
0
File: Main.cs Project: kleril/Lemma
		public void SaveWithNotification(bool overwrite)
		{
			if (!this.saving && !this.Paused && this.Menu.CanPause && this.MapFile != Main.MenuMap && !this.IsChallengeMap(this.MapFile) && PlayerFactory.Instance != null)
			{
				this.saving = true;
				Container saveNotification = new Container();
				saveNotification.Tint.Value = Microsoft.Xna.Framework.Color.Black;
				saveNotification.Opacity.Value = UIFactory.Opacity;
				TextElement saveNotificationText = new TextElement();
				saveNotificationText.Name.Value = "Text";
				saveNotificationText.FontFile.Value = this.Font;
				saveNotificationText.Text.Value = "\\saving";
				saveNotification.Children.Add(saveNotificationText);
				this.UI.Root.GetChildByName("Notifications").Children.Add(saveNotification);
				this.AddComponent(new Animation
				(
					new Animation.Delay(0.01f),
					new Animation.Execute(delegate()
					{
						if (overwrite)
							this.SaveOverwrite();
						else
							this.SaveNew();
					}),
					new Animation.Delay(0.01f),
					new Animation.Set<string>(saveNotificationText.Text, "\\saved"),
					new Animation.Parallel
					(
						new Animation.FloatMoveTo(saveNotification.Opacity, 0.0f, 1.0f),
						new Animation.FloatMoveTo(saveNotificationText.Opacity, 0.0f, 1.0f)
					),
					new Animation.Execute(saveNotification.Delete),
					new Animation.Execute(delegate()
					{
						this.saving = false;
					})
				));
			}
		}
Example #19
0
		public static void Bind(Entity entity, Main main, ListContainer commandQueueContainer)
		{
			PCInput input = entity.Get<PCInput>();
			Editor editor = entity.Get<Editor>();
			EditorGeeUI gui = entity.Get<EditorGeeUI>();
			Property<bool> analyticsEnable = new Property<bool>();
			ListProperty<SessionEntry> analyticsSessions = new ListProperty<SessionEntry>();
			ListProperty<SessionEntry> analyticsActiveSessions = new ListProperty<SessionEntry>();
			ListProperty<EventEntry> analyticsEvents = new ListProperty<EventEntry>();
			ListProperty<EventEntry> analyticsActiveEvents = new ListProperty<EventEntry>();
			ListProperty<PropertyEntry> analyticsProperties = new ListProperty<PropertyEntry>();
			ListProperty<PropertyEntry> analyticsActiveProperties = new ListProperty<PropertyEntry>();
			Dictionary<Session, ModelInstance> sessionPositionModels = new Dictionary<Session, ModelInstance>();
			Dictionary<Session.EventList, List<ModelInstance>> eventPositionModels = new Dictionary<Session.EventList, List<ModelInstance>>();
			Property<bool> analyticsPlaying = new Property<bool>();
			Property<float> playbackSpeed = new Property<float> { Value = 1.0f };
			Property<float> playbackLocation = new Property<float>();

			const float timelineHeight = 32.0f;

			Scroller timelineScroller = new Scroller();
			timelineScroller.ScrollAmount.Value = 60.0f;
			timelineScroller.EnableScissor.Value = false;
			timelineScroller.DefaultScrollHorizontal.Value = true;
			timelineScroller.AnchorPoint.Value = new Vector2(0, 1);
			timelineScroller.ResizeVertical.Value = true;
			timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Position, x => new Vector2(0, x.Y), main.ScreenSize));
			timelineScroller.Add(new Binding<Vector2, Point>(timelineScroller.Size, x => new Vector2(x.X, timelineHeight), main.ScreenSize));
			timelineScroller.Add(new Binding<bool>(timelineScroller.Visible, () => analyticsEnable && Editor.EditorModelsVisible, analyticsEnable, Editor.EditorModelsVisible));
			timelineScroller.Add(new Binding<bool>(timelineScroller.EnableScroll, x => !x, input.GetKey(Keys.LeftAlt)));
			entity.Add(new CommandBinding(entity.Delete, timelineScroller.Delete));
			main.UI.Root.Children.Add(timelineScroller);

			timelineScroller.Add(new Binding<bool>(editor.EnableCameraDistanceScroll, () => !timelineScroller.Highlighted || editor.VoxelEditMode, timelineScroller.Highlighted, editor.VoxelEditMode));
			timelineScroller.Add(new CommandBinding(timelineScroller.Delete, delegate()
			{
				editor.EnableCameraDistanceScroll.Value = true;
			}));

			ListContainer timelines = new ListContainer();
			timelines.Alignment.Value = ListContainer.ListAlignment.Min;
			timelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
			timelines.Reversed.Value = true;
			timelineScroller.Children.Add(timelines);

			input.Add(new CommandBinding<int>(input.MouseScrolled, () => input.GetKey(Keys.LeftAlt) && timelineScroller.Highlighted && !editor.VoxelEditMode, delegate(int delta)
			{
				float newScale = Math.Max(timelines.Scale.Value.X + delta * 6.0f, timelineScroller.Size.Value.X / timelines.Size.Value.X);
				Matrix absoluteTransform = timelines.GetAbsoluteTransform();
				float x = input.Mouse.Value.X + ((absoluteTransform.Translation.X - input.Mouse.Value.X) * (newScale / timelines.Scale.Value.X));
				timelines.Position.Value = new Vector2(x, 0.0f);
				timelines.Scale.Value = new Vector2(newScale, 1.0f);
			}));

			Container timeline = new Container();
			timeline.Size.Value = new Vector2(0, timelineHeight);
			timeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			timeline.ResizeHorizontal.Value = false;
			timeline.ResizeVertical.Value = false;
			timelines.Children.Add(timeline);

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Load analytics data", new PCInput.Chord(),
				new Command
				{
					Action = delegate()
					{
						if (main.MapFile.Value != null)
						{
							List<Session> sessions = main.LoadAnalytics(main.MapFile);
							if (sessions.Count > 0)
							{
								analyticsEnable.Value = true;
								Dictionary<string, bool> distinctEventNames = new Dictionary<string, bool>();
								Dictionary<string, bool> distinctPropertyNames = new Dictionary<string, bool>();
								foreach (Session s in sessions)
								{
									foreach (Session.EventList el in s.Events)
									{
										distinctEventNames[el.Name] = true;
										s.TotalTime = Math.Max(s.TotalTime, el.Events[el.Events.Count - 1].Time);
									}
									foreach (Session.ContinuousProperty p in s.ContinuousProperties)
									{
										if (p.Independent)
											distinctPropertyNames[p.Name] = true;
									}
									analyticsSessions.Add(new SessionEntry { Session = s });
								}
								analyticsEvents.AddAll(distinctEventNames.Keys.Select(x => new EventEntry { Name = x }));
								analyticsProperties.AddAll(distinctPropertyNames.Keys.Select(x => new PropertyEntry { Name = x }));
								timeline.Size.Value = new Vector2(analyticsSessions.Max(x => x.Session.TotalTime), timelineScroller.Size.Value.Y);
								timelines.Scale.Value = new Vector2(timelineScroller.Size.Value.X / timeline.Size.Value.X, 1.0f);
							}
						}
					}
				},
				gui.MapCommands,
				() => !analyticsEnable && !string.IsNullOrEmpty(main.MapFile) && !gui.PickNextEntity,
				analyticsEnable, main.MapFile, gui.PickNextEntity
			);

			ListContainer sessionsSidebar = new ListContainer();
			sessionsSidebar.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Add(new Binding<Vector2>(sessionsSidebar.Position, () => new Vector2(main.ScreenSize.Value.X - 10, main.ScreenSize.Value.Y - timelineScroller.ScaledSize.Value.Y - 10), main.ScreenSize, timelineScroller.ScaledSize));
			sessionsSidebar.Add(new Binding<bool>(sessionsSidebar.Visible, () => analyticsEnable && Editor.EditorModelsVisible, analyticsEnable, Editor.EditorModelsVisible));
			sessionsSidebar.Alignment.Value = ListContainer.ListAlignment.Max;
			sessionsSidebar.Reversed.Value = true;
			main.UI.Root.Children.Add(sessionsSidebar);
			entity.Add(new CommandBinding(entity.Delete, sessionsSidebar.Delete));

			Func<string, ListContainer> createCheckboxListItem = delegate(string text)
			{
				ListContainer layout = new ListContainer();
				layout.Orientation.Value = ListContainer.ListOrientation.Horizontal;

				TextElement label = new TextElement();
				label.FontFile.Value = main.Font;
				label.Text.Value = text;
				label.Name.Value = "Label";
				layout.Children.Add(label);

				Container checkboxContainer = new Container();
				checkboxContainer.PaddingBottom.Value = checkboxContainer.PaddingLeft.Value = checkboxContainer.PaddingRight.Value = checkboxContainer.PaddingTop.Value = 1.0f;
				layout.Children.Add(checkboxContainer);

				Container checkbox = new Container();
				checkbox.Name.Value = "Checkbox";
				checkbox.ResizeHorizontal.Value = checkbox.ResizeVertical.Value = false;
				checkbox.Size.Value = new Vector2(16.0f, 16.0f);
				checkboxContainer.Children.Add(checkbox);
				return layout;
			};

			Container sessionsContainer = new Container();
			sessionsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			sessionsContainer.Opacity.Value = UIFactory.Opacity;
			sessionsContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(sessionsContainer);

			Scroller sessionsScroller = new Scroller();
			sessionsScroller.ResizeHorizontal.Value = true;
			sessionsScroller.ResizeVertical.Value = true;
			sessionsScroller.MaxVerticalSize.Value = 256;
			sessionsContainer.Children.Add(sessionsScroller);

			ListContainer sessionList = new ListContainer();
			sessionList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			sessionList.Alignment.Value = ListContainer.ListAlignment.Max;
			sessionsScroller.Children.Add(sessionList);

			Property<bool> allSessions = new Property<bool>();

			sessionList.Add(new ListBinding<UIComponent, SessionEntry>(sessionList.Children, analyticsSessions, delegate(SessionEntry entry)
			{
				ListContainer item = createCheckboxListItem(string.Format("{0} {1:d} ({2})", entry.Session.UUID.Substring(0, 8), entry.Session.Date, new TimeSpan(0, 0, (int)entry.Session.TotalTime)));

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, entry.Active));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (entry.Active)
					{
						allSessions.Value = false;
						analyticsActiveSessions.Remove(entry);
					}
					else
						analyticsActiveSessions.Add(entry);
				}));

				return item;
			}));

			ListContainer allSessionsButton = createCheckboxListItem("[All]");
			allSessionsButton.Add(new CommandBinding(allSessionsButton.MouseLeftDown, delegate()
			{
				if (allSessions)
				{
					allSessions.Value = false;
					foreach (SessionEntry s in analyticsActiveSessions.ToList())
						analyticsActiveSessions.Remove(s);
				}
				else
				{
					allSessions.Value = true;
					foreach (SessionEntry s in analyticsSessions)
					{
						if (!s.Active)
							analyticsActiveSessions.Add(s);
					}
				}
			}));

			Container allSessionsCheckbox = (Container)allSessionsButton.GetChildByName("Checkbox");
			allSessionsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allSessionsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allSessions));
			sessionList.Children.Add(allSessionsButton);

			Container eventsContainer = new Container();
			eventsContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			eventsContainer.Opacity.Value = UIFactory.Opacity;
			eventsContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(eventsContainer);

			Scroller eventsScroller = new Scroller();
			eventsScroller.ResizeHorizontal.Value = true;
			eventsScroller.ResizeVertical.Value = true;
			eventsScroller.MaxVerticalSize.Value = 256;
			eventsContainer.Children.Add(eventsScroller);

			ListContainer eventList = new ListContainer();
			eventList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			eventList.Alignment.Value = ListContainer.ListAlignment.Max;
			eventsScroller.Children.Add(eventList);

			Property<bool> allEvents = new Property<bool>();

			eventList.Add(new ListBinding<UIComponent, EventEntry>(eventList.Children, analyticsEvents, delegate(EventEntry e)
			{
				ListContainer item = createCheckboxListItem(e.Name);

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

				TextElement label = (TextElement)item.GetChildByName("Label");
				label.Tint.Value = new Microsoft.Xna.Framework.Color(colorHash(e.Name));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (e.Active)
					{
						allEvents.Value = false;
						analyticsActiveEvents.Remove(e);
					}
					else
						analyticsActiveEvents.Add(e);
				}));

				return item;
			}));

			ListContainer allEventsButton = createCheckboxListItem("[All]");
			allEventsButton.Add(new CommandBinding(allEventsButton.MouseLeftDown, delegate()
			{
				if (allEvents)
				{
					allEvents.Value = false;
					foreach (EventEntry e in analyticsActiveEvents.ToList())
						analyticsActiveEvents.Remove(e);
				}
				else
				{
					allEvents.Value = true;
					foreach (EventEntry e in analyticsEvents)
					{
						if (!e.Active)
							analyticsActiveEvents.Add(e);
					}
				}
			}));
			Container allEventsCheckbox = (Container)allEventsButton.GetChildByName("Checkbox");
			allEventsCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allEventsCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allEvents));
			eventList.Children.Add(allEventsButton);

			Container propertiesContainer = new Container();
			propertiesContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			propertiesContainer.Opacity.Value = UIFactory.Opacity;
			propertiesContainer.AnchorPoint.Value = new Vector2(1, 1);
			sessionsSidebar.Children.Add(propertiesContainer);

			Scroller propertiesScroller = new Scroller();
			propertiesScroller.ResizeHorizontal.Value = true;
			propertiesScroller.ResizeVertical.Value = true;
			propertiesScroller.MaxVerticalSize.Value = 256;
			propertiesContainer.Children.Add(propertiesScroller);

			ListContainer propertiesList = new ListContainer();
			propertiesList.Orientation.Value = ListContainer.ListOrientation.Vertical;
			propertiesList.Alignment.Value = ListContainer.ListAlignment.Max;
			propertiesScroller.Children.Add(propertiesList);

			Property<bool> allProperties = new Property<bool>();

			propertiesList.Add(new ListBinding<UIComponent, PropertyEntry>(propertiesList.Children, analyticsProperties, delegate(PropertyEntry e)
			{
				ListContainer item = createCheckboxListItem(e.Name);

				Container checkbox = (Container)item.GetChildByName("Checkbox");
				checkbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(checkbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, e.Active));

				TextElement label = (TextElement)item.GetChildByName("Label");
				label.Tint.Value = new Microsoft.Xna.Framework.Color(colorHash(e.Name));

				item.Add(new CommandBinding(item.MouseLeftDown, delegate()
				{
					if (e.Active)
					{
						allProperties.Value = false;
						analyticsActiveProperties.Remove(e);
					}
					else
						analyticsActiveProperties.Add(e);
				}));

				return item;
			}));

			ListContainer allPropertiesButton = createCheckboxListItem("[All]");
			allPropertiesButton.Add(new CommandBinding(allPropertiesButton.MouseLeftDown, delegate()
			{
				if (allProperties)
				{
					allProperties.Value = false;
					foreach (PropertyEntry e in analyticsActiveProperties.ToList())
						analyticsActiveProperties.Remove(e);
				}
				else
				{
					allProperties.Value = true;
					foreach (PropertyEntry e in analyticsProperties)
					{
						if (!e.Active)
							analyticsActiveProperties.Add(e);
					}
				}
			}));
			Container allPropertiesCheckbox = (Container)allPropertiesButton.GetChildByName("Checkbox");
			allPropertiesCheckbox.Add(new Binding<Microsoft.Xna.Framework.Color, bool>(allPropertiesCheckbox.Tint, x => x ? Microsoft.Xna.Framework.Color.White : Microsoft.Xna.Framework.Color.Black, allProperties));
			propertiesList.Children.Add(allPropertiesButton);

			Func<Session.EventList, LineDrawer2D> createEventLines = delegate(Session.EventList el)
			{
				LineDrawer2D line = new LineDrawer2D();
				line.Color.Value = colorHash(el.Name);
				line.UserData.Value = el;

				foreach (Session.Event e in el.Events)
				{
					line.Lines.Add(new LineDrawer2D.Line
					{
						A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, 0.0f, 0.0f), Microsoft.Xna.Framework.Color.White),
						B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor(new Vector3(e.Time, timeline.Size.Value.Y, 0.0f), Microsoft.Xna.Framework.Color.White),
					});
				}
				return line;
			};

			analyticsActiveEvents.ItemAdded += delegate(int index, EventEntry ee)
			{
				ee.Active.Value = true;
				foreach (SessionEntry s in analyticsActiveSessions)
				{
					Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
					foreach (Session.EventList el in s.Session.Events)
					{
						if (el.Name == ee.Name)
						{
							List<ModelInstance> models = new List<ModelInstance>();
							Vector4 color = colorHash(el.Name);
							int hash = (int)(new Color(color).PackedValue);
							foreach (Session.Event e in el.Events)
							{
								ModelInstance i = new ModelInstance();
								i.Serialize = false;
								i.Setup("InstancedModels\\position-model", hash);
								if (i.IsFirstInstance)
									i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
								i.Transform.Value = Matrix.CreateTranslation(positionProperty.GetLastRecordedPosition(e.Time));
								models.Add(i);
								entity.Add(i);
							}
							eventPositionModels[el] = models;
						}
					}

					timeline.Children.AddAll(s.Session.Events.Where(x => x.Name == ee.Name).Select(createEventLines));
				}
			};

			analyticsActiveEvents.ItemRemoved += delegate(int index, EventEntry e)
			{
				e.Active.Value = false;
				foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
				{
					if (pair.Key.Name == e.Name)
					{
						foreach (ModelInstance instance in pair.Value)
							instance.Delete.Execute();
						eventPositionModels.Remove(pair.Key);
					}
				}
				timeline.Children.RemoveAll(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Name == e.Name).ToList());
			};

			analyticsActiveProperties.ItemAdded += delegate(int index, PropertyEntry e)
			{
				e.Active.Value = true;
			};

			analyticsActiveProperties.ItemRemoved += delegate(int index, PropertyEntry e)
			{
				e.Active.Value = false;
			};

			ListContainer propertyTimelines = new ListContainer();
			propertyTimelines.Alignment.Value = ListContainer.ListAlignment.Min;
			propertyTimelines.Orientation.Value = ListContainer.ListOrientation.Vertical;
			timelines.Children.Add(propertyTimelines);

			Action<Container> refreshPropertyGraph = delegate(Container container)
			{
				TextElement label = (TextElement)container.GetChildByName("Label");
				LineDrawer2D lines = (LineDrawer2D)container.GetChildByName("Graph");
				string propertyName = ((PropertyEntry)lines.UserData.Value).Name;
				lines.Lines.Clear();
				float time = 0.0f, lastTime = 0.0f;
				float lastValue = 0.0f;
				bool firstLine = true;
				float max = float.MinValue, min = float.MaxValue;
				while (true)
				{
					bool stop = true;

					// Calculate average
					int count = 0;
					float sum = 0.0f;
					foreach (SessionEntry s in analyticsActiveSessions)
					{
						if (time < s.Session.TotalTime)
						{
							Session.ContinuousProperty prop = s.Session.GetContinuousProperty(propertyName);
							if (prop != null)
							{
								stop = false;
								sum += prop[time];
								count++;
							}
						}
					}

					if (stop)
						break;
					else
					{
						float value = sum / (float)count;
						if (firstLine)
							firstLine = false;
						else
						{
							lines.Lines.Add(new LineDrawer2D.Line
							{
								A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
								{
									Color = Microsoft.Xna.Framework.Color.White,
									Position = new Vector3(lastTime, lastValue, 0.0f),
								},
								B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
								{
									Color = Microsoft.Xna.Framework.Color.White,
									Position = new Vector3(time, value, 0.0f),
								},
							});
						}
						min = Math.Min(min, value);
						max = Math.Max(max, value);
						lastValue = value;
						lastTime = time;
						time += Session.Recorder.Interval;
					}

					if (min < max)
					{
						float scale = -timelineHeight / (max - min);
						lines.Scale.Value = new Vector2(1, scale);
						lines.Position.Value = new Vector2(0, max * -scale);
					}
					else
					{
						lines.AnchorPoint.Value = Vector2.Zero;
						if (min <= 0.0f)
							lines.Position.Value = new Vector2(0, timelineHeight);
						else
							lines.Position.Value = new Vector2(0, timelineHeight * 0.5f);
					}
					label.Text.Value = max.ToString("F");
				}
			};

			Action refreshPropertyGraphs = delegate()
			{
				foreach (Container propertyTimeline in propertyTimelines.Children)
					refreshPropertyGraph(propertyTimeline);
			};

			propertyTimelines.Add(new ListBinding<UIComponent, PropertyEntry>(propertyTimelines.Children, analyticsActiveProperties, delegate(PropertyEntry e)
			{
				Container propertyTimeline = new Container();
				propertyTimeline.Add(new Binding<Vector2>(propertyTimeline.Size, timeline.Size));
				propertyTimeline.Tint.Value = Microsoft.Xna.Framework.Color.Black;
				propertyTimeline.Opacity.Value = UIFactory.Opacity;
				propertyTimeline.ResizeHorizontal.Value = false;
				propertyTimeline.ResizeVertical.Value = false;

				LineDrawer2D line = new LineDrawer2D();
				line.Name.Value = "Graph";
				line.Color.Value = colorHash(e.Name);
				line.UserData.Value = e;
				propertyTimeline.Children.Add(line);

				TextElement label = new TextElement();
				label.FontFile.Value = main.Font;
				label.Name.Value = "Label";
				label.Add(new Binding<Vector2>(label.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
				label.AnchorPoint.Value = new Vector2(0, 0);
				label.Position.Value = new Vector2(0, 0);
				propertyTimeline.Children.Add(label);

				refreshPropertyGraph(propertyTimeline);

				return propertyTimeline;
			}));

			analyticsActiveSessions.ItemAdded += delegate(int index, SessionEntry s)
			{
				Session.PositionProperty positionProperty = s.Session.PositionProperties[0];
				foreach (Session.EventList el in s.Session.Events)
				{
					if (analyticsActiveEvents.FirstOrDefault(x => x.Name == el.Name) != null)
					{
						List<ModelInstance> models = new List<ModelInstance>();
						Vector4 color = colorHash(el.Name);
						int hash = (int)(new Color(color).PackedValue);
						foreach (Session.Event e in el.Events)
						{
							ModelInstance i = new ModelInstance();
							i.Serialize = false;
							i.Setup("InstancedModels\\position-model", hash);
							if (i.IsFirstInstance)
								i.Model.Color.Value = new Vector3(color.X, color.Y, color.Z);
							i.Transform.Value = Matrix.CreateTranslation(positionProperty.GetLastRecordedPosition(e.Time));
							entity.Add(i);
							models.Add(i);
						}
						eventPositionModels[el] = models;
					}
				}

				ModelInstance instance = new ModelInstance();
				instance.Setup("InstancedModels\\position-model", 0);
				instance.Serialize = false;
				entity.Add(instance);
				sessionPositionModels.Add(s.Session, instance);
				s.Active.Value = true;
				timeline.Children.AddAll(s.Session.Events.Where(x => analyticsActiveEvents.FirstOrDefault(y => y.Name == x.Name) != null).Select(createEventLines));
				playbackLocation.Reset();

				refreshPropertyGraphs();
			};

			analyticsActiveSessions.ItemRemoved += delegate(int index, SessionEntry s)
			{
				ModelInstance instance = sessionPositionModels[s.Session];
				instance.Delete.Execute();

				foreach (KeyValuePair<Session.EventList, List<ModelInstance>> pair in eventPositionModels.ToList())
				{
					if (pair.Key.Session == s.Session)
					{
						foreach (ModelInstance i in pair.Value)
							i.Delete.Execute();
						eventPositionModels.Remove(pair.Key);
					}
				}

				sessionPositionModels.Remove(s.Session);
				s.Active.Value = false;
				timeline.Children.RemoveAll(timeline.Children.Where(x => x.UserData.Value != null && ((Session.EventList)x.UserData.Value).Session == s.Session).ToList());

				refreshPropertyGraphs();
			};

			entity.Add(new SetBinding<float>(playbackLocation, delegate(float value)
			{
				if (analyticsActiveSessions.Length == 0)
					return;

				if (value < 0.0f)
					playbackLocation.Value = 0.0f;
				float end = analyticsActiveSessions.Max(x => x.Session.TotalTime);
				if (value > end)
				{
					playbackLocation.Value = end;
					analyticsPlaying.Value = false;
				}

				foreach (KeyValuePair<Session, ModelInstance> pair in sessionPositionModels)
					pair.Value.Transform.Value = Matrix.CreateTranslation(pair.Key.PositionProperties[0][playbackLocation]);
			}));

			LineDrawer2D playbackLine = new LineDrawer2D();
			playbackLine.Color.Value = Vector4.One;
			playbackLine.Lines.Add(new LineDrawer2D.Line
			{
				A = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
				{
					Color = Microsoft.Xna.Framework.Color.White,
					Position = new Vector3(0.0f, -10.0f, 0.0f),
				},
				B = new Microsoft.Xna.Framework.Graphics.VertexPositionColor
				{
					Color = Microsoft.Xna.Framework.Color.White,
					Position = new Vector3(0.0f, timeline.Size.Value.Y, 0.0f),
				},
			});
			playbackLine.Add(new Binding<Vector2, float>(playbackLine.Position, x => new Vector2(x, 0.0f), playbackLocation));
			timeline.Children.Add(playbackLine);

			entity.Add(new NotifyBinding(delegate()
			{
				allEventsButton.Detach();
				allSessionsButton.Detach();
				allPropertiesButton.Detach();
				analyticsSessions.Clear();
				analyticsEvents.Clear();
				analyticsProperties.Clear();
				eventList.Children.Add(allEventsButton);
				sessionList.Children.Add(allSessionsButton);
				propertiesList.Children.Add(allPropertiesButton);

				foreach (ModelInstance instance in sessionPositionModels.Values)
					instance.Delete.Execute();
				sessionPositionModels.Clear();

				foreach (ModelInstance instance in eventPositionModels.Values.SelectMany(x => x))
					instance.Delete.Execute();
				eventPositionModels.Clear();

				allEvents.Value = false;
				allSessions.Value = false;
				allProperties.Value = false;
				analyticsEnable.Value = false;

				analyticsActiveEvents.Clear();
				analyticsActiveSessions.Clear();
				analyticsActiveProperties.Clear();

				propertyTimelines.Children.Clear();

				playbackLine.Detach();
				timeline.Children.Clear();
				timeline.Children.Add(playbackLine);

				analyticsPlaying.Value = false;
				playbackLocation.Value = 0.0f;
			}, main.MapFile));

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Toggle analytics playback", new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.A },  new Command
				{
					Action = delegate()
					{
						analyticsPlaying.Value = !analyticsPlaying;
					}
				},
				gui.MapCommands,
				() => analyticsEnable && !editor.MovementEnabled && analyticsActiveSessions.Length > 0,
				analyticsEnable, editor.MovementEnabled, analyticsActiveSessions.Length
			);

			EditorFactory.AddCommand
			(
				entity, main, commandQueueContainer, "Stop analytics playback", new PCInput.Chord { Key = Keys.Escape }, new Command
				{
					Action = delegate()
					{
						analyticsPlaying.Value = false;
					}
				}, gui.MapCommands, () => analyticsPlaying, analyticsPlaying
			);

			Container playbackContainer = new Container();
			playbackContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			playbackContainer.Opacity.Value = UIFactory.Opacity;
			sessionsSidebar.Children.Add(playbackContainer);
			playbackContainer.Add(new CommandBinding<int>(playbackContainer.MouseScrolled, delegate(int delta)
			{
				playbackSpeed.Value = Math.Max(1.0f, Math.Min(10.0f, playbackSpeed.Value + delta));
			}));

			TextElement playbackLabel = new TextElement();
			playbackLabel.FontFile.Value = main.Font;
			playbackLabel.Add(new Binding<string>(playbackLabel.Text, delegate()
			{
				return string.Format("{0} {1} {2:F}x", TimeTrialUI.SecondsToTimeString(playbackLocation), (analyticsPlaying ? "Playing" : "Stopped"), playbackSpeed);
			}, playbackLocation, playbackSpeed, analyticsPlaying));
			playbackContainer.Children.Add(playbackLabel);

			Container descriptionContainer = null;

			Updater timelineUpdate = new Updater
			(
				delegate(float dt)
				{
					bool setTimelinePosition = false;

					if (timelines.Highlighted || descriptionContainer != null)
					{
						if (input.LeftMouseButton)
						{
							setTimelinePosition = true;
							playbackLocation.Value = Vector3.Transform(new Vector3(input.Mouse.Value.X, 0.0f, 0.0f), Matrix.Invert(timeline.GetAbsoluteTransform())).X;
						}

						float threshold = 3.0f / timelines.Scale.Value.X;
						float mouseRelative = Vector3.Transform(new Vector3(input.Mouse, 0.0f), Matrix.Invert(timelines.GetAbsoluteTransform())).X;

						if (descriptionContainer != null)
						{
							if (!timelines.Highlighted || (float)Math.Abs(descriptionContainer.Position.Value.X - mouseRelative) > threshold)
							{
								descriptionContainer.Delete.Execute();
								descriptionContainer = null;
							}
						}

						if (descriptionContainer == null && timeline.Highlighted)
						{
							foreach (UIComponent component in timeline.Children)
							{
								LineDrawer2D lines = component as LineDrawer2D;

								if (lines == null)
									continue;

								Session.EventList el = lines.UserData.Value as Session.EventList;
								if (el != null)
								{
									bool stop = false;
									foreach (Session.Event e in el.Events)
									{
										if (el != null && (float)Math.Abs(e.Time - mouseRelative) < threshold)
										{
											descriptionContainer = new Container();
											descriptionContainer.AnchorPoint.Value = new Vector2(0.5f, 1.0f);
											descriptionContainer.Position.Value = new Vector2(e.Time, 0.0f);
											descriptionContainer.Opacity.Value = 1.0f;
											descriptionContainer.Tint.Value = Microsoft.Xna.Framework.Color.Black;
											descriptionContainer.Add(new Binding<Vector2>(descriptionContainer.Scale, x => new Vector2(1.0f / x.X, 1.0f / x.Y), timelines.Scale));
											timeline.Children.Add(descriptionContainer);
											TextElement description = new TextElement();
											description.WrapWidth.Value = 256;

											if (string.IsNullOrEmpty(e.Data))
												description.Text.Value = el.Name;
											else
												description.Text.Value = string.Format("{0}\n{1}", el.Name, e.Data);

											description.FontFile.Value = main.Font;
											descriptionContainer.Children.Add(description);
											stop = true;
											break;
										}
									}
									if (stop)
										break;
								}
							}
						}
					}

					if (analyticsPlaying && !setTimelinePosition)
					{
						if (analyticsActiveSessions.Length == 0)
							analyticsPlaying.Value = false;
						else
							playbackLocation.Value += dt * playbackSpeed;
					}
				}
			);
			entity.Add(timelineUpdate);
			timelineUpdate.EnabledInEditMode = true;
		}
Example #20
0
File: Main.cs Project: kleril/Lemma
		protected override void LoadContent()
		{
			this.MapContent = new ContentManager(this.Services);
			this.MapContent.RootDirectory = this.Content.RootDirectory;

			GeeUIMain.Font = this.Content.Load<SpriteFont>(this.Font);

			if (this.firstLoadContentCall)
			{
				this.firstLoadContentCall = false;

				if (!Directory.Exists(this.MapDirectory))
					Directory.CreateDirectory(this.MapDirectory);
				string challengeDirectory = Path.Combine(this.MapDirectory, "Challenge");
				if (!Directory.Exists(challengeDirectory))
					Directory.CreateDirectory(challengeDirectory);

#if VR
				if (this.VR)
				{
					this.vrLeftMesh.Load(this, Ovr.Eye.Left, this.vrLeftFov);
					this.vrRightMesh.Load(this, Ovr.Eye.Right, this.vrRightFov);
					new CommandBinding(this.ReloadedContent, (Action)this.vrLeftMesh.Reload);
					new CommandBinding(this.ReloadedContent, (Action)this.vrRightMesh.Reload);
					this.reallocateVrTargets();

					this.vrCamera = new Camera();
					this.AddComponent(this.vrCamera);
				}
#endif

				this.GraphicsDevice.PresentationParameters.PresentationInterval = PresentInterval.Immediate;
				this.GeeUI = new GeeUIMain();
				this.AddComponent(GeeUI);

				this.ConsoleUI = new ConsoleUI();
				this.AddComponent(ConsoleUI);

				this.Console = new Console.Console();
				this.AddComponent(Console);

				Lemma.Console.Console.BindType(null, this);
				Lemma.Console.Console.BindType(null, Console);

				// Initialize Wwise
				AkGlobalSoundEngineInitializer initializer = new AkGlobalSoundEngineInitializer(Path.Combine(this.Content.RootDirectory, "Wwise"));
				this.AddComponent(initializer);

				this.Listener = new AkListener();
				this.Listener.Add(new Binding<Vector3>(this.Listener.Position, this.Camera.Position));
				this.Listener.Add(new Binding<Vector3>(this.Listener.Forward, this.Camera.Forward));
				this.Listener.Add(new Binding<Vector3>(this.Listener.Up, this.Camera.Up));
				this.AddComponent(this.Listener);

				// Create the renderer.
				this.LightingManager = new LightingManager();
				this.AddComponent(this.LightingManager);
				this.Renderer = new Renderer(this, true, true, true, true, true);

				this.AddComponent(this.Renderer);
				this.Renderer.ReallocateBuffers(this.ScreenSize);

				this.renderParameters = new RenderParameters
				{
					Camera = this.Camera,
					IsMainRender = true
				};

				// Load strings
				this.Strings.Load(Path.Combine(this.Content.RootDirectory, "Strings.xlsx"));

				this.UI = new UIRenderer();
				this.UI.GeeUI = this.GeeUI;
				this.AddComponent(this.UI);

				PCInput input = new PCInput();
				this.AddComponent(input);

				Lemma.Console.Console.BindType(null, input);
				Lemma.Console.Console.BindType(null, UI);
				Lemma.Console.Console.BindType(null, Renderer);
				Lemma.Console.Console.BindType(null, LightingManager);

				input.Add(new CommandBinding(input.GetChord(new PCInput.Chord { Modifier = Keys.LeftAlt, Key = Keys.S }), delegate()
				{
					// High-resolution screenshot
					bool originalModelsVisible = Editor.EditorModelsVisible;
					Editor.EditorModelsVisible.Value = false;
					Screenshot s = new Screenshot();
					this.AddComponent(s);
					s.Take(new Point(4096, 2304), delegate()
					{
						string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
						string path;
						int i = 0;
						do
						{
							path = Path.Combine(desktop, string.Format("lemma-screen{0}.png", i));
							i++;
						}
						while (File.Exists(path));

						Screenshot.SavePng(s.Buffer, path);

						Editor.EditorModelsVisible.Value = originalModelsVisible;

						s.Delete.Execute();
					});
				}));

				this.performanceMonitor = new ListContainer();
				this.performanceMonitor.Add(new Binding<Vector2, Point>(performanceMonitor.Position, x => new Vector2(x.X, 0), this.ScreenSize));
				this.performanceMonitor.AnchorPoint.Value = new Vector2(1, 0);
				this.performanceMonitor.Visible.Value = false;
				this.performanceMonitor.Name.Value = "PerformanceMonitor";
				this.UI.Root.Children.Add(this.performanceMonitor);

				Action<string, Property<double>> addTimer = delegate(string label, Property<double> property)
				{
					TextElement text = new TextElement();
					text.FontFile.Value = this.Font;
					text.Add(new Binding<string, double>(text.Text, x => label + ": " + (x * 1000.0).ToString("F") + "ms", property));
					this.performanceMonitor.Children.Add(text);
				};

				Action<string, Property<int>> addCounter = delegate(string label, Property<int> property)
				{
					TextElement text = new TextElement();
					text.FontFile.Value = this.Font;
					text.Add(new Binding<string, int>(text.Text, x => label + ": " + x.ToString(), property));
					this.performanceMonitor.Children.Add(text);
				};

				TextElement frameRateText = new TextElement();
				frameRateText.FontFile.Value = this.Font;
				frameRateText.Add(new Binding<string, float>(frameRateText.Text, x => "FPS: " + x.ToString("0"), this.frameRate));
				this.performanceMonitor.Children.Add(frameRateText);

				addTimer("Physics", this.physicsTime);
				addTimer("Update", this.updateTime);
				addTimer("Render", this.renderTime);
				addCounter("Draw calls", this.drawCalls);
				addCounter("Triangles", this.triangles);
				addCounter("Working set", this.workingSet);

				Lemma.Console.Console.AddConCommand(new ConCommand("perf", "Toggle the performance monitor", delegate(ConCommand.ArgCollection args)
				{
					this.performanceMonitor.Visible.Value = !this.performanceMonitor.Visible;
				}));

				try
				{
					IEnumerable<string> globalStaticScripts = Directory.GetFiles(Path.Combine(this.Content.RootDirectory, "GlobalStaticScripts"), "*", SearchOption.AllDirectories).Select(x => Path.Combine("..\\GlobalStaticScripts", Path.GetFileNameWithoutExtension(x)));
					foreach (string scriptName in globalStaticScripts)
						this.executeStaticScript(scriptName);
				}
				catch (IOException)
				{

				}

				this.UIFactory = new UIFactory();
				this.AddComponent(this.UIFactory);
				this.AddComponent(this.Menu); // Have to do this here so the menu's Awake can use all our loaded stuff

				this.Spawner = new Spawner();
				this.AddComponent(this.Spawner);

				this.UI.IsMouseVisible.Value = true;

				AKRESULT akresult = AkBankLoader.LoadBank("SFX_Bank_01.bnk");
				if (akresult != AKRESULT.AK_Success)
					Log.d(string.Format("Failed to load main sound bank: {0}", akresult));

#if ANALYTICS
				this.SessionRecorder = new Session.Recorder(this);

				this.SessionRecorder.Add("Position", delegate()
				{
					Entity p = PlayerFactory.Instance;
					if (p != null && p.Active)
						return p.Get<Transform>().Position;
					else
						return Vector3.Zero;
				});

				this.SessionRecorder.Add("Health", delegate()
				{
					Entity p = PlayerFactory.Instance;
					if (p != null && p.Active)
						return p.Get<Player>().Health;
					else
						return 0.0f;
				});

				this.SessionRecorder.Add("Framerate", delegate()
				{
					return this.frameRate;
				});

				this.SessionRecorder.Add("WorkingSet", delegate()
				{
					return this.workingSet;
				});
				this.AddComponent(this.SessionRecorder);
				this.SessionRecorder.Add(new Binding<bool, Config.RecordAnalytics>(this.SessionRecorder.EnableUpload, x => x == Config.RecordAnalytics.On, this.Settings.Analytics));
#endif

				this.DefaultLighting();

				new SetBinding<float>(this.Settings.SoundEffectVolume, delegate(float value)
				{
					AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.VOLUME_SFX, MathHelper.Clamp(value, 0.0f, 1.0f));
				});

				new SetBinding<float>(this.Settings.MusicVolume, delegate(float value)
				{
					AkSoundEngine.SetRTPCValue(AK.GAME_PARAMETERS.VOLUME_MUSIC, MathHelper.Clamp(value, 0.0f, 1.0f));
				});

				new TwoWayBinding<LightingManager.DynamicShadowSetting>(this.Settings.DynamicShadows, this.LightingManager.DynamicShadows);
				new TwoWayBinding<float>(this.Settings.MotionBlurAmount, this.Renderer.MotionBlurAmount);
				new TwoWayBinding<float>(this.Settings.Gamma, this.Renderer.Gamma);
				new TwoWayBinding<bool>(this.Settings.Bloom, this.Renderer.EnableBloom);
				new TwoWayBinding<bool>(this.Settings.SSAO, this.Renderer.EnableSSAO);
				new Binding<float>(this.Camera.FieldOfView, this.Settings.FieldOfView);

				foreach (string file in Directory.GetFiles(this.MapDirectory, "*.xlsx", SearchOption.TopDirectoryOnly))
					this.Strings.Load(file);

				new Binding<string, Config.Lang>(this.Strings.Language, x => x.ToString(), this.Settings.Language);
				new NotifyBinding(this.SaveSettings, this.Settings.Language);

				new CommandBinding(this.MapLoaded, delegate()
				{
					this.Renderer.BlurAmount.Value = 0.0f;
					this.Renderer.Tint.Value = new Vector3(1.0f);
				});

#if VR
				if (this.VR)
				{
					Action loadVrEffect = delegate()
					{
						this.vrEffect = this.Content.Load<Effect>("Effects\\Oculus");
					};
					loadVrEffect();
					new CommandBinding(this.ReloadedContent, loadVrEffect);

					this.UI.Add(new Binding<Point>(this.UI.RenderTargetSize, this.ScreenSize));

					this.VRUI = new Lemma.Components.ModelNonPostProcessed();
					this.VRUI.MapContent = false;
					this.VRUI.DrawOrder.Value = 100000; // On top of everything
					this.VRUI.Filename.Value = "Models\\plane";
					this.VRUI.EffectFile.Value = "Effects\\VirtualUI";
					this.VRUI.Add(new Binding<Microsoft.Xna.Framework.Graphics.RenderTarget2D>(this.VRUI.GetRenderTarget2DParameter("Diffuse" + Lemma.Components.Model.SamplerPostfix), this.UI.RenderTarget));
					this.VRUI.Add(new Binding<Matrix>(this.VRUI.Transform, delegate()
					{
						Matrix rot = this.Camera.RotationMatrix;
						Matrix mat = Matrix.Identity;
						mat.Forward = rot.Right;
						mat.Right = rot.Forward;
						mat.Up = rot.Up;
						mat *= Matrix.CreateScale(7);
						mat.Translation = this.Camera.Position + rot.Forward * 4.0f;
						return mat;
					}, this.Camera.Position, this.Camera.RotationMatrix));
					this.AddComponent(this.VRUI);

					this.UI.Setup3D(this.VRUI.Transform);
				}
#endif

#if ANALYTICS
				bool editorLastEnabled = this.EditorEnabled;
				new CommandBinding<string>(this.LoadingMap, delegate(string newMap)
				{
					if (this.MapFile.Value != null && !editorLastEnabled)
					{
						this.SessionRecorder.RecordEvent("ChangedMap", newMap);
						if (!this.IsChallengeMap(this.MapFile) && this.MapFile.Value != Main.MenuMap)
							this.SaveAnalytics();
					}
					this.SessionRecorder.Reset();
					editorLastEnabled = this.EditorEnabled;
				});
#endif
				new CommandBinding<string>(this.LoadingMap, delegate(string newMap)
				{
					this.CancelScheduledSave();
				});

#if !DEVELOPMENT
				IO.MapLoader.Load(this, MenuMap);
				this.Menu.Show(initial: true);
#endif

#if ANALYTICS
				if (this.Settings.Analytics.Value == Config.RecordAnalytics.Ask)
				{
					this.Menu.ShowDialog("\\analytics prompt", "\\enable analytics", delegate()
					{
						this.Settings.Analytics.Value = Config.RecordAnalytics.On;
					},
					"\\disable analytics", delegate()
					{
						this.Settings.Analytics.Value = Config.RecordAnalytics.Off;
					});
				}
#endif

#if VR
				if (this.oculusNotFound)
					this.Menu.HideMessage(null, this.Menu.ShowMessage(null, "Error: no Oculus found."), 6.0f);

				if (this.VR)
				{
					this.Menu.EnableInput(false);
					Container vrMsg = this.Menu.BuildMessage("\\vr message", 300.0f);
					vrMsg.AnchorPoint.Value = new Vector2(0.5f, 0.5f);
					vrMsg.Add(new Binding<Vector2, Point>(vrMsg.Position, x => new Vector2(x.X * 0.5f, x.Y * 0.5f), this.ScreenSize));
					this.UI.Root.Children.Add(vrMsg);
					input.Bind(this.Settings.RecenterVRPose, PCInput.InputState.Down, this.VRHmd.RecenterPose);
					input.Bind(this.Settings.RecenterVRPose, PCInput.InputState.Down, delegate()
					{
						if (vrMsg != null)
						{
							vrMsg.Delete.Execute();
							vrMsg = null;
						}
						this.Menu.EnableInput(true);
					});
				}
				else
#endif
				{
					input.Bind(this.Settings.ToggleFullscreen, PCInput.InputState.Down, delegate()
					{
						if (this.Settings.Fullscreen) // Already fullscreen. Go to windowed mode.
							this.ExitFullscreen();
						else // In windowed mode. Go to fullscreen.
							this.EnterFullscreen();
					});
				}

				input.Bind(this.Settings.QuickSave, PCInput.InputState.Down, delegate()
				{
					this.SaveWithNotification(true);
				});
			}
			else
			{
				this.ReloadingContent.Execute();
				foreach (IGraphicsComponent c in this.graphicsComponents)
					c.LoadContent(true);
				this.ReloadedContent.Execute();
			}

			this.GraphicsDevice.RasterizerState = new RasterizerState { MultiSampleAntiAlias = false };

			if (this.spriteBatch != null)
				this.spriteBatch.Dispose();
			this.spriteBatch = new SpriteBatch(this.GraphicsDevice);
		}
Example #21
0
		public static void Run(Entity script)
		{
			const float fadeTime = 1.0f;

			main.Spawner.CanSpawn = false;

			Sprite logo = new Sprite();
			logo.Image.Value = "Images\\logo";
			logo.AnchorPoint.Value = new Vector2(0.5f, 0.5f);
			main.UI.Root.Children.Insert(0, logo);

			if (main.Spawner.StartSpawnPoint.Value == "demo")
			{
				main.UI.IsMouseVisible.Value = true;
				logo.Add(new Binding<Vector2, Point>(logo.Position, x => new Vector2(x.X * 0.5f, x.Y * 0.4f), main.ScreenSize));
				
				Container listContainer = main.UIFactory.CreateContainer();
				listContainer.Opacity.Value = 0.5f;
				listContainer.PaddingLeft.Value = listContainer.PaddingRight.Value = listContainer.PaddingBottom.Value = listContainer.PaddingTop.Value = 8.0f * main.FontMultiplier;
				listContainer.Add(new Binding<Vector2, Point>(listContainer.Position, x => new Vector2(x.X * 0.5f, x.Y * 0.65f), main.ScreenSize));
				listContainer.AnchorPoint.Value = new Vector2(0.5f, 0.5f);
				listContainer.Opacity.Value = 0.0f;
				script.Add(new Animation
				(
					new Animation.Delay(1.0f),
					new Animation.FloatMoveTo(listContainer.Opacity, 1.0f, fadeTime)
				));

				ListContainer list = new ListContainer();
				list.Spacing.Value = 8.0f * main.FontMultiplier;
				list.Alignment.Value = ListContainer.ListAlignment.Middle;
				listContainer.Children.Add(list);
				main.UI.Root.Children.Insert(1, listContainer);

				script.Add(new CommandBinding(script.Delete, listContainer.Delete));

				Action<string> addText = delegate(string text)
				{
					TextElement element = new TextElement();
					element.FontFile.Value = main.Font;
					element.Text.Value = text;
					element.Add(new Binding<float, Vector2>(element.WrapWidth, x => x.X, logo.ScaledSize));
					element.Opacity.Value = 0.0f;
					script.Add(new Animation
					(
						new Animation.Delay(1.0f),
						new Animation.FloatMoveTo(element.Opacity, 1.0f, fadeTime)
					));
					list.Children.Add(element);
				};

				Action<string, string> addLink = delegate(string text, string url)
				{
					TextElement element = main.UIFactory.CreateLink(text, url);
					element.Add(new Binding<float, Vector2>(element.WrapWidth, x => x.X, logo.ScaledSize));
					element.Opacity.Value = 0.0f;
					script.Add(new Animation
					(
						new Animation.Delay(1.0f),
						new Animation.FloatMoveTo(element.Opacity, 1.0f, fadeTime)
					));
					list.Children.Add(element);
				};

				addText("Thanks for trying the demo!");
				addText("If you enjoyed it, please consider buying a Steam key from one of these venues:");

				addLink("itch.io (best dev cut)", "http://et1337.itch.io/lemma");
				addLink("Steam (direct)", "http://store.steampowered.com/app/300340");
			}
			else
				logo.Add(new Binding<Vector2, Point>(logo.Position, x => new Vector2(x.X * 0.5f, x.Y * 0.5f), main.ScreenSize));

			Container cornerContainer = main.UIFactory.CreateContainer();
			cornerContainer.AnchorPoint.Value = new Vector2(1, 0);
			cornerContainer.PaddingLeft.Value = cornerContainer.PaddingRight.Value = 12.0f;
			#if VR
			if (main.VR)
				cornerContainer.Add(new Binding<Vector2, Point>(cornerContainer.Position, x => new Vector2(x.X * 0.75f, x.Y * 0.25f), main.ScreenSize));
			else
			#endif
				cornerContainer.Add(new Binding<Vector2, Point>(cornerContainer.Position, x => new Vector2(x.X - 10.0f, 10.0f), main.ScreenSize));
			main.UI.Root.Children.Add(cornerContainer);

			ListContainer corner = new ListContainer();
			corner.Orientation.Value = ListContainer.ListOrientation.Horizontal;
			corner.Alignment.Value = ListContainer.ListAlignment.Middle;
			corner.Spacing.Value = 12.0f;
			cornerContainer.Children.Add(corner);

			TextElement version = new TextElement();
			version.FontFile.Value = main.Font;
			version.Add(new Binding<string>(version.Text, x => string.Format(main.Strings.Get("build number") ?? "Build {0}", Main.Build.ToString()), main.Strings.Language));
			corner.Children.Add(version);

			TextElement webLink = main.UIFactory.CreateLink("et1337.com", "http://et1337.com");
			corner.Children.Add(webLink);

			Container languageMenu = new Container();

			Container languageButton = main.UIFactory.CreateButton(delegate()
			{
				languageMenu.Visible.Value = !languageMenu.Visible;
			});
			corner.Children.Add(languageButton);

			Sprite currentLanguageIcon = new Sprite();
			currentLanguageIcon.Add(new Binding<string, Main.Config.Lang>(currentLanguageIcon.Image, x => "Images\\" + x.ToString(), main.Settings.Language));
			languageButton.Children.Add(currentLanguageIcon);

			languageMenu.Tint.Value = Microsoft.Xna.Framework.Color.Black;
			languageMenu.Visible.Value = false;
			languageMenu.AnchorPoint.Value = new Vector2(1, 0);
			cornerContainer.CheckLayout();
			languageMenu.Add(new Binding<Vector2>(languageMenu.Position, () => languageButton.GetAbsolutePosition() + new Vector2(languageButton.ScaledSize.Value.X, languageButton.ScaledSize.Value.Y), languageButton.Position, languageButton.ScaledSize, cornerContainer.Position));
			main.UI.Root.Children.Add(languageMenu);
			
			ListContainer languages = new ListContainer();
			languages.Orientation.Value = ListContainer.ListOrientation.Vertical;
			languages.Alignment.Value = ListContainer.ListAlignment.Max;
			languages.Spacing.Value = 0.0f;
			languageMenu.Children.Add(languages);
			
			foreach (Main.Config.Lang language in Enum.GetValues(typeof(Main.Config.Lang)))
			{
				UIComponent button = main.UIFactory.CreateButton(delegate()
				{
					main.Settings.Language.Value = language;
					languageMenu.Visible.Value = false;
				});

				Sprite icon = new Sprite();
				icon.Image.Value = "Images\\" + language.ToString();
				button.Children.Add(icon);

				languages.Children.Add(button);
			}

			logo.Opacity.Value = 0.0f;
			version.Opacity.Value = 0.0f;
			cornerContainer.Opacity.Value = 0.0f;
			webLink.Opacity.Value = 0.0f;
			languageButton.Opacity.Value = 0.0f;
			currentLanguageIcon.Opacity.Value = 0.0f;

			script.Add(new Animation
			(
				new Animation.Delay(1.0f),
				new Animation.Parallel
				(
					new Animation.FloatMoveTo(logo.Opacity, 1.0f, fadeTime),
					new Animation.FloatMoveTo(version.Opacity, 1.0f, fadeTime),
					new Animation.FloatMoveTo(cornerContainer.Opacity, UIFactory.Opacity, fadeTime),
					new Animation.FloatMoveTo(webLink.Opacity, 1.0f, fadeTime),
					new Animation.FloatMoveTo(languageButton.Opacity, UIFactory.Opacity, fadeTime),
					new Animation.FloatMoveTo(currentLanguageIcon.Opacity, 1.0f, fadeTime)
				)
			));

			script.Add(new CommandBinding(script.Delete, logo.Delete, cornerContainer.Delete, languageMenu.Delete));

			main.Renderer.InternalGamma.Value = 0.0f;
			main.Renderer.Brightness.Value = 0.0f;
			main.Renderer.Tint.Value = new Vector3(0.0f);
			script.Add(new Animation
			(
				new Animation.Vector3MoveTo(main.Renderer.Tint, new Vector3(1.0f), 0.3f)
			));

			if (main.Settings.GodModeProperty)
				SteamWorker.SetAchievement("cheevo_god_mode");
			else
			{
				int konamiIndex = 0;
				PCInput input = script.Create<PCInput>();
				input.Add(new CommandBinding<PCInput.PCInputBinding>(input.AnyInputDown, delegate(PCInput.PCInputBinding button)
				{
					if (!main.Settings.GodModeProperty)
					{
						if (button.Key == konamiCode[konamiIndex].Key || button.GamePadButton == konamiCode[konamiIndex].GamePadButton)
						{
							if (konamiIndex == konamiCode.Length - 1)
							{
								main.Settings.GodModeProperty.Value = true;
								main.SaveSettings();
								SteamWorker.SetAchievement("cheevo_god_mode");
								main.Menu.HideMessage(script, main.Menu.ShowMessage(script, "\\god mode"), 5.0f);
							}
							else
								konamiIndex++;
						}
						else
						{
							konamiIndex = 0;
							if (button.Key == konamiCode[konamiIndex].Key || button.GamePadButton == konamiCode[konamiIndex].GamePadButton)
								konamiIndex++;
						}
					}
				}));
			}
		}