diff --git a/puzzle course.csproj b/puzzle course.csproj index ffd5f33..32a35bf 100644 --- a/puzzle course.csproj +++ b/puzzle course.csproj @@ -1,4 +1,4 @@ - + net6.0 net7.0 diff --git a/puzzle course.csproj.old.1 b/puzzle course.csproj.old.1 new file mode 100644 index 0000000..ffd5f33 --- /dev/null +++ b/puzzle course.csproj.old.1 @@ -0,0 +1,9 @@ + + + net6.0 + net7.0 + net8.0 + true + puzzlecourse + + \ No newline at end of file diff --git a/resources/building/BuildingResource.cs b/resources/building/BuildingResource.cs index 6ac78a8..0671329 100644 --- a/resources/building/BuildingResource.cs +++ b/resources/building/BuildingResource.cs @@ -11,6 +11,9 @@ public partial class BuildingResource : Resource [Export] public string Description { get; private set; } + [Export] + public bool IsBase { get; private set; } + [Export] public bool IsDeletable { get; private set; } = true; diff --git a/resources/building/base.tres b/resources/building/base.tres index 41aa452..310e0cd 100644 --- a/resources/building/base.tres +++ b/resources/building/base.tres @@ -6,9 +6,13 @@ [resource] script = ExtResource("1_ccreb") DisplayName = "Base" +Description = "" +IsBase = true IsDeletable = false Dimensions = Vector2i(5, 2) ResourceCost = 0 BuildableRadius = 6 ResourceRadius = 0 +DangerRadius = 0 +AttackRadius = 0 BuildingScene = ExtResource("1_ei3r1") diff --git a/scenes/level/Level3.tscn b/scenes/level/Level3.tscn index d2898fd..fa02dc6 100644 --- a/scenes/level/Level3.tscn +++ b/scenes/level/Level3.tscn @@ -43,6 +43,6 @@ position = Vector2(1216, 192) position = Vector2(0, 896) [node name="GoblinCamp" parent="YSortRoot" index="4" instance=ExtResource("5_o0rsf")] -position = Vector2(192, 640) +position = Vector2(-512, 192) [editable path="YSortRoot/BaseTerrainTileMapLayer/ElevationLayer"] diff --git a/scenes/manager/BuildingManager.cs b/scenes/manager/BuildingManager.cs index 56d3bcc..6c193f9 100644 --- a/scenes/manager/BuildingManager.cs +++ b/scenes/manager/BuildingManager.cs @@ -191,6 +191,8 @@ private void DestroyBuildAtHoveredCellPosition() ); if (buildingComponent == null) return; + if (!gridManager.CanDestroyBuilidng(buildingComponent)) + return; currentlyUsedResourceCount -= buildingComponent.BuildingResource.ResourceCost; buildingComponent.Destroy(); diff --git a/scenes/manager/GridManager.cs b/scenes/manager/GridManager.cs index 71800bb..31223b3 100644 --- a/scenes/manager/GridManager.cs +++ b/scenes/manager/GridManager.cs @@ -36,6 +36,7 @@ public partial class GridManager : Node private List allTilemapLayers = new(); private Dictionary tileMapLayerToElevationLayer = new(); + private Dictionary> buildingToBuildableTiles = new(); public override void _Ready() { @@ -184,6 +185,91 @@ public Vector2I ConvertWorldPositionToTilePosition(Vector2 worldPosition) return (Vector2I)(worldPosition / 64).Floor(); } + public bool CanDestroyBuilidng(BuildingComponent toDestroyBuildingComponent) + { + if (toDestroyBuildingComponent.BuildingResource.BuildableRadius > 0) + { + var dependentBuildings = BuildingComponent + .GetValidBuildingComponents(this) + .Where(x => + x.GetTileArea() + .ToTiles() + .Any( + (tilePosition) => + buildingToBuildableTiles[toDestroyBuildingComponent] + .Contains(tilePosition) + ) + && x != toDestroyBuildingComponent + && !x.BuildingResource.IsBase + ); + + var allBuildingsStillValid = dependentBuildings.All( + (dependentBuilding) => + { + var tilesForBuilding = dependentBuilding.GetTileArea().ToTiles(); + return tilesForBuilding.All(tilePosition => + buildingToBuildableTiles + .Keys.Where(key => + key != toDestroyBuildingComponent && key != dependentBuilding + ) + .Any(key => buildingToBuildableTiles[key].Contains(tilePosition)) + ); + } + ); + if (!allBuildingsStillValid) + return false; + + return IsBuildingNetworkConnected(toDestroyBuildingComponent); + } + return true; + } + + private bool IsBuildingNetworkConnected(BuildingComponent toDestroyBuildingComponent) + { + var baseBuilding = BuildingComponent + .GetValidBuildingComponents(this) + .First(x => x.BuildingResource.IsBase); + var visitedBuildings = new HashSet(); + VisitAllConnectedBuildings(baseBuilding, toDestroyBuildingComponent, visitedBuildings); + + var totalBuildingsToVisit = BuildingComponent + .GetValidBuildingComponents(this) + .Count(x => x != toDestroyBuildingComponent && x.BuildingResource.BuildableRadius > 0); + return totalBuildingsToVisit == visitedBuildings.Count; + } + + private void VisitAllConnectedBuildings( + BuildingComponent rootBuilding, + BuildingComponent excludeBuilding, + HashSet visitedBuildings + ) + { + var dependentBuildings = BuildingComponent + .GetValidBuildingComponents(this) + .Where(x => + { + if (x.BuildingResource.BuildableRadius == 0) + return false; + if (visitedBuildings.Contains(x)) + return false; + + return x.GetTileArea() + .ToTiles() + .Any( + (tilePosition) => + buildingToBuildableTiles[rootBuilding].Contains(tilePosition) + ) + && x != excludeBuilding; + }) + .ToList(); + + visitedBuildings.UnionWith(dependentBuildings); + foreach (var building in dependentBuildings) + { + VisitAllConnectedBuildings(building, excludeBuilding, visitedBuildings); + } + } + private HashSet GetBuildableTileSet(bool isAttackTiles = false) { return isAttackTiles ? validBuildableAttackTiles : validBuildableTiles; @@ -252,18 +338,22 @@ private void UpdateValidBuildableTiles(BuildingComponent buildingComponent) occupiedTiles.UnionWith(buildingComponent.GetOccupiedCellPositions()); var tileArea = buildingComponent.GetTileArea(); - var allTiles = GetTilesInRadius( - tileArea, - buildingComponent.BuildingResource.BuildableRadius, - (_) => true - ); - allTilesInBuildingRadius.UnionWith(allTiles); + if (buildingComponent.BuildingResource.BuildableRadius > 0) + { + var allTiles = GetTilesInRadius( + tileArea, + buildingComponent.BuildingResource.BuildableRadius, + (_) => true + ); + allTilesInBuildingRadius.UnionWith(allTiles); - var validTiles = GetValidTilesInRadius( - tileArea, - buildingComponent.BuildingResource.BuildableRadius - ); - validBuildableTiles.UnionWith(validTiles); + var validTiles = GetValidTilesInRadius( + tileArea, + buildingComponent.BuildingResource.BuildableRadius + ); + buildingToBuildableTiles[buildingComponent] = validTiles.ToHashSet(); + validBuildableTiles.UnionWith(validTiles); + } validBuildableTiles.ExceptWith(occupiedTiles); validBuildableAttackTiles.UnionWith(validBuildableTiles); @@ -312,6 +402,7 @@ private void RecalculateGrid() collectedResourceTiles.Clear(); goblinOccupiedTiles.Clear(); attackTiles.Clear(); + buildingToBuildableTiles.Clear(); var buildingComponents = BuildingComponent.GetValidBuildingComponents(this); foreach (var buildingComponent in buildingComponents) @@ -403,7 +494,7 @@ private List GetResourceTilesInRadius(Rect2I tileArea, int radius) ); } - public void UpdateBuildingComponentGridState(BuildingComponent buildingComponent) + private void UpdateBuildingComponentGridState(BuildingComponent buildingComponent) { UpdateGoblinOccupiedTiles(buildingComponent); UpdateValidBuildableTiles(buildingComponent);