✨ New sfx and vfx and features in building
This commit is contained in:
		| @@ -11,7 +11,7 @@ public partial class PlacementManager : Node2D | ||||
|     [Export] public GridManager Grid { get; set; } | ||||
|     [Export] public ResourceManager Inventory { get; set; } | ||||
|     [Export] public BuildingRegistry Registry { get; set; } | ||||
|      | ||||
|  | ||||
|     [Export] public int MaxConcurrentBuilds { get; set; } = 6; // Make it adjustable in editor | ||||
|     [Export] public bool Enabled { get; set; } = true; | ||||
|     [Export] public StringName ToggleBuildAction { get; set; } = "toggle_build"; | ||||
| @@ -19,33 +19,50 @@ public partial class PlacementManager : Node2D | ||||
|     private static readonly List<string> BuildableTiles = ["wall", "miner"]; | ||||
|     private readonly Dictionary<Node2D, BuildTask> _buildTasks = new(); | ||||
|     private AudioStreamPlayer _completionSound; | ||||
|     private AudioStreamPlayer _buildingSound; | ||||
|     private AudioStreamPlayer _canceledSound; | ||||
|     private AudioStreamPlayer _cannotDeploySound; | ||||
|     private AudioStreamPlayer _notReadySound; | ||||
|     private AudioStreamPlayer _insufficientFundsSound; | ||||
|     private Node2D _currentGhost; // Keep track of the current ghost building | ||||
|  | ||||
|     public override void _Ready() | ||||
|     { | ||||
|         base._Ready(); | ||||
|          | ||||
|  | ||||
|         // Setup completion sound | ||||
|         _completionSound = new AudioStreamPlayer(); | ||||
|         AddChild(_completionSound); | ||||
|         var sound = GD.Load<AudioStream>("res://Sounds/Events/ConstructionComplete.wav"); | ||||
|         _completionSound = CreateAudioPlayer("res://Sounds/Events/ConstructionComplete.wav"); | ||||
|         _buildingSound = CreateAudioPlayer("res://Sounds/Events/Building.wav"); | ||||
|         _canceledSound = CreateAudioPlayer("res://Sounds/Events/Canceled.wav"); | ||||
|         _cannotDeploySound = CreateAudioPlayer("res://Sounds/Events/CannotDeployHere.wav"); | ||||
|         _notReadySound = CreateAudioPlayer("res://Sounds/Events/NotReady.wav"); | ||||
|         _insufficientFundsSound = CreateAudioPlayer("res://Sounds/Events/InsufficientFunds.wav"); | ||||
|     } | ||||
|  | ||||
|     private AudioStreamPlayer CreateAudioPlayer(string path) | ||||
|     { | ||||
|         var player = new AudioStreamPlayer(); | ||||
|         AddChild(player); | ||||
|         var sound = GD.Load<AudioStream>(path); | ||||
|         if (sound != null) | ||||
|         { | ||||
|             _completionSound.Stream = sound; | ||||
|             player.Stream = sound; | ||||
|         } | ||||
|  | ||||
|         return player; | ||||
|     } | ||||
|  | ||||
|     private void OnBuildCompleted() | ||||
|     { | ||||
|         // Remove all completed builds | ||||
|         var completed = _buildTasks.Where(kvp => kvp.Value.IsCompleted) | ||||
|                                 .Select(kvp => kvp.Key) | ||||
|                                 .ToList(); | ||||
|             .Select(kvp => kvp.Key) | ||||
|             .ToList(); | ||||
|         foreach (var key in completed) | ||||
|         { | ||||
|             _buildTasks.Remove(key); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         // If no builds left, play the completion sound | ||||
|         if (_buildTasks.Count == 0) | ||||
|         { | ||||
| @@ -58,13 +75,13 @@ public partial class PlacementManager : Node2D | ||||
|     { | ||||
|         // Remove completed builds | ||||
|         var completed = _buildTasks.Where(kvp => kvp.Value.IsCompleted) | ||||
|                                 .Select(kvp => kvp.Key) | ||||
|                                 .ToList(); | ||||
|             .Select(kvp => kvp.Key) | ||||
|             .ToList(); | ||||
|         foreach (var key in completed) | ||||
|         { | ||||
|             _buildTasks.Remove(key); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         return _buildTasks.Count < MaxConcurrentBuilds; | ||||
|     } | ||||
|  | ||||
| @@ -76,7 +93,7 @@ public partial class PlacementManager : Node2D | ||||
|         public void Complete(bool wasCancelled = false) | ||||
|         { | ||||
|             if (IsCompleted) return; | ||||
|              | ||||
|  | ||||
|             IsCompleted = true; | ||||
|             WasCancelled = wasCancelled; | ||||
|             onCompleted?.Invoke(); | ||||
| @@ -158,7 +175,7 @@ public partial class PlacementManager : Node2D | ||||
|     public override void _Process(double delta) | ||||
|     { | ||||
|         if (!Enabled) return; | ||||
|          | ||||
|  | ||||
|         // Snap mouse to grid | ||||
|         var mousePos = GetGlobalMousePosition(); | ||||
|         var newHoveredCell = GridUtils.WorldToGrid(mousePos); | ||||
| @@ -194,24 +211,25 @@ public partial class PlacementManager : Node2D | ||||
|         _ghostBuilding.SetGhostMode(canPlace); | ||||
|  | ||||
|         // Left click to place | ||||
|         if (Input.IsActionPressed("build_tile") && canPlace) | ||||
|         if (Input.IsActionPressed("build_tile")) | ||||
|         { | ||||
|             var building = Registry.GetBuilding(_currentBuildingId); | ||||
|             if (building == null) return; | ||||
|              | ||||
|  | ||||
|             if (!CanStartNewBuild()) | ||||
|             { | ||||
|                 // Optionally show feedback to player that build queue is full | ||||
|                 _notReadySound.Play(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Consume resources first | ||||
|             if (!ConsumeBuildingResources(_currentBuildingId)) | ||||
|             { | ||||
|                 // Optionally show feedback to player that they can't afford this building | ||||
|                 _insufficientFundsSound.Play(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Create the building instance first | ||||
|             var scene = building.Scene; | ||||
|             var buildingInstance = (BaseTile)scene.Instantiate(); | ||||
|             buildingInstance.RotationDegrees = _currentRotation; | ||||
| @@ -219,23 +237,30 @@ public partial class PlacementManager : Node2D | ||||
|             buildingInstance.Position = _ghostBuilding.Position; | ||||
|             AddChild(buildingInstance); | ||||
|  | ||||
|             // Check if area is free before placing | ||||
|             // First check if area is free | ||||
|             if (!IsAreaFree(_hoveredCell, building.Size, _currentRotation, building.Layer)) | ||||
|             { | ||||
|                 _cannotDeploySound.Play(); | ||||
|                 RefundBuildingResources(_currentBuildingId); | ||||
|                 buildingInstance.QueueFree(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Occupy the area | ||||
|             // If we get here, area is free, so we can safely occupy it | ||||
|             Grid.OccupyArea(_hoveredCell, buildingInstance, building.Size, _currentRotation, building.Layer); | ||||
|  | ||||
|             if (building.BuildTime > 0f) | ||||
|             { | ||||
|                 var wasQueueEmpty = _buildTasks.Count == 0; | ||||
|                 var buildTask = new BuildTask(OnBuildCompleted); | ||||
|                 _buildTasks[buildingInstance] = buildTask; | ||||
|                  | ||||
|                 buildingInstance.StartConstruction(building.BuildTime, () => { | ||||
|  | ||||
|                 // Play building sound only when adding to an empty queue | ||||
|                 if (wasQueueEmpty) | ||||
|                     _buildingSound.Play(); | ||||
|  | ||||
|                 buildingInstance.StartConstruction(building.BuildTime, () => | ||||
|                 { | ||||
|                     // On construction complete | ||||
|                     if (_buildTasks.TryGetValue(buildingInstance, out var task)) | ||||
|                     { | ||||
| @@ -245,6 +270,7 @@ public partial class PlacementManager : Node2D | ||||
|                             Grid.FreeArea(_hoveredCell, building.Size, _currentRotation, building.Layer); | ||||
|                             buildingInstance.QueueFree(); | ||||
|                         } | ||||
|  | ||||
|                         task.Complete(); | ||||
|                         _buildTasks.Remove(buildingInstance); | ||||
|                     } | ||||
| @@ -258,9 +284,28 @@ public partial class PlacementManager : Node2D | ||||
|             // Right click to destroy from current layer | ||||
|             var building = Grid.GetBuildingAtCell(_hoveredCell); | ||||
|             if (building == null) return; | ||||
|              | ||||
|             // Find all cells occupied by this building | ||||
|             var buildingInfo = Grid.GetBuildingInfoAtCell(_hoveredCell, GridLayer.Building); | ||||
|             if (buildingInfo == null) return; | ||||
|              | ||||
|             // Check if this building is in the build tasks (under construction) | ||||
|             if (_buildTasks.TryGetValue(building, out var buildTask)) | ||||
|             { | ||||
|                 var buildingTile = building as BaseTile; | ||||
|                 // Cancel the build task | ||||
|                 buildTask.Complete(true); // Mark as cancelled | ||||
|                 _buildTasks.Remove(building); | ||||
|                 _canceledSound.Play(); | ||||
|                 if (buildingTile == null) return; | ||||
|                  | ||||
|                 // Refund resources for canceled build | ||||
|                 var buildingData = Registry.GetBuilding(buildingTile.TileId); | ||||
|                 if (buildingData != null) | ||||
|                     RefundBuildingResources(buildingTile.TileId); | ||||
|             } | ||||
|              | ||||
|             // Clean up the building and grid | ||||
|             building.QueueFree(); | ||||
|             Grid.FreeArea(buildingInfo.Value.Position, buildingInfo.Value.Size, buildingInfo.Value.Rotation); | ||||
|         } | ||||
| @@ -278,7 +323,7 @@ public partial class PlacementManager : Node2D | ||||
|         if (@event.IsActionPressed(ToggleBuildAction)) | ||||
|         { | ||||
|             Enabled = !Enabled; | ||||
|              | ||||
|  | ||||
|             // Hide ghost building when disabling | ||||
|             if (!Enabled && _ghostBuilding != null && _ghostBuilding.IsInsideTree()) | ||||
|             { | ||||
| @@ -297,41 +342,41 @@ public partial class PlacementManager : Node2D | ||||
|     private bool CanAffordBuilding(string buildingId) | ||||
|     { | ||||
|         if (Inventory == null) return false; | ||||
|          | ||||
|  | ||||
|         var buildingData = Registry.GetBuilding(buildingId); | ||||
|         if (buildingData == null) return false; | ||||
|          | ||||
|  | ||||
|         // Check if we have enough of each required resource | ||||
|         foreach (var (resourceId, amount) in buildingData.Cost) | ||||
|             if (!Inventory.HasResource(resourceId, amount)) | ||||
|                 return false; | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     private bool ConsumeBuildingResources(string buildingId) | ||||
|     { | ||||
|         if (Inventory == null) return false; | ||||
|          | ||||
|  | ||||
|         var buildingData = Registry.GetBuilding(buildingId); | ||||
|         if (buildingData == null) return false; | ||||
|          | ||||
|  | ||||
|         // First verify we can afford it | ||||
|         if (!CanAffordBuilding(buildingId)) return false; | ||||
|          | ||||
|  | ||||
|         // Then consume each resource | ||||
|         foreach (var (resourceId, amount) in buildingData.Cost) | ||||
|             Inventory.RemoveResource(resourceId, amount); | ||||
|          | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     private void RefundBuildingResources(string buildingId) | ||||
|     { | ||||
|         if (Inventory == null) return; | ||||
|          | ||||
|  | ||||
|         var buildingData = Registry.GetBuilding(buildingId); | ||||
|         if (buildingData == null) return; | ||||
|          | ||||
|  | ||||
|         // Refund each resource | ||||
|         foreach (var (resourceId, amount) in buildingData.Cost) | ||||
|         { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user