using System.Collections.Generic; using System.Linq; using Godot; using Godot.Collections; public partial class ResearchList : PanelContainer { [Export] private GraphEdit researchGraph; private const float StartXDivisor = 32f; private const float StartYDivisor = 4f; private const float NodeSpacingMultiplier = 10f; private List reloadKeys = new List(); public override void _Ready() { RecalculateResearchStates(); SetupGraph(); } public void SetupGraph() { reloadKeys = new List(); ClearGraph(); CreateResearchNodes(); CreateResearchConnections(); } private void ClearGraph() { foreach (Dictionary connection in researchGraph.GetConnectionList()) { researchGraph.DisconnectNode( connection["from_node"].AsStringName(), (int)connection["from_port"], connection["to_node"].AsStringName(), (int)connection["to_port"] ); } foreach (Node child in researchGraph.GetChildren()) { if (child is GraphNode) { researchGraph.RemoveChild(child); child.QueueFree(); } } } private void CreateResearchNodes() { foreach (Research research in GameData.availableResearch.Values) { GD.Print(research.state); GraphNode node = CreateResearchNode( research.data.Id, research.data.Texture, research.state ); researchGraph.AddChild(node); } } private void CreateResearchConnections() { foreach (Research research in GameData.availableResearch.Values) { string prerequisite = research.data.Research; string current = research.data.Id; if (string.IsNullOrEmpty(prerequisite)) continue; if (!researchGraph.HasNode(prerequisite) || !researchGraph.HasNode(current)) continue; researchGraph.ConnectNode( prerequisite, 0, current, 0 ); } } private GraphNode CreateResearchNode(string id, string texturePath, ResearchState state) { Texture2D texture = GD.Load(texturePath); Color stateColor = GetColorByState(state); TextureRect icon = new TextureRect { Texture = texture, StretchMode = TextureRect.StretchModeEnum.KeepAspectCentered, CustomMinimumSize = new Vector2(64, 64), SelfModulate = stateColor }; Button button = new Button { Text = "Research", Disabled = state != ResearchState.AVAILABLE }; button.Pressed += () => OnResearchPressed(id); GraphNode node = new GraphNode { Name = id, Title = id, PositionOffset = GetNodePosition(texture), SelfModulate = stateColor }; node.SetSlot( 0, true, 0, Colors.White, true, 0, Colors.White ); node.AddChild(icon); node.AddChild(button); return node; } private Vector2 GetNodePosition(Texture2D texture) { Vector2 viewportSize = GetViewport().GetVisibleRect().Size; float textureWidth = texture?.GetWidth() ?? 64f; Vector2 startPosition = new Vector2( viewportSize.X / StartXDivisor, viewportSize.Y / StartYDivisor ); float xOffset = GameData.availableResearch.Count * -textureWidth + researchGraph.GetChildCount() * textureWidth * NodeSpacingMultiplier; return startPosition + new Vector2(xOffset, 0); } private void OnResearchPressed(string id) { GameData.availableResearch[id].state = ResearchState.RESEARCHED; RecalculateResearchStates(); SetupGraph(); } private void RecalculateResearchStates() { bool changedState; foreach (string key in GameData.availableResearch.Keys) { changedState = false; if (reloadKeys.Contains(key)) continue; reloadKeys.Add(key); //Already researched if (GameData.availableResearch[key].state == ResearchState.RESEARCHED) { changedState = true; } //No previous research needed if (GameData.availableResearch[key].data.Research.Length <= 0) { GameData.availableResearch[key].state = ResearchState.RESEARCHED; changedState = true; } //Previous research is unlocked if (!changedState && GameData.availableResearch[GameData.availableResearch[key].data.Research].state == ResearchState.RESEARCHED) { GameData.availableResearch[key].state = ResearchState.AVAILABLE; changedState = true; } if (!changedState) { //All others are locked GameData.availableResearch[key].state = ResearchState.LOCKED; } if (reloadKeys.Count != GameData.availableResearch.Keys.Count) { RecalculateResearchStates(); } } } private Color GetColorByState(ResearchState state) { return state switch { ResearchState.AVAILABLE => Colors.White, ResearchState.LOCKED => new Color(0.6f, 0.6f, 0.6f, 0.5f), ResearchState.RESEARCHED => new Color(0.7f, 1f, 0.7f, 1f), _ => Colors.Red }; } }