Ver Fonte

Resources now end

Axel Nordh há 4 meses atrás
pai
commit
76690c9f50

+ 4 - 0
Assets/Scripts/BuildingSystem.cs

@@ -372,6 +372,10 @@ public class BuildingSystem : MonoBehaviour
                 if (newBuilding.GetComponent<SimpleFarmhouse>() == null)
                     newBuilding.AddComponent<SimpleFarmhouse>();
             }
+            else if (selectedBuildingTemplate.name == "Builder's Workshop")
+            {
+                newBuilding.tag = "BuildingWorkshop"; // Tag for builder job requirement
+            }
 
             Debug.Log($"Instantly placed {selectedBuildingTemplate.name} at {position}");
         }

+ 58 - 19
Assets/Scripts/Field.cs

@@ -1,4 +1,5 @@
 using UnityEngine;
+using UnityEngine.InputSystem;
 
 public enum FieldSize
 {
@@ -7,24 +8,26 @@ public enum FieldSize
     Large = 3    // 3x3, slow to work, high yield
 }
 
-public class Field : MonoBehaviour
+public class Field : MonoBehaviour, ISelectable
 {
     [Header("Field Properties")]
     public FieldSize fieldSize = FieldSize.Small;
     public int maxFood = 30;
     public int currentFood = 0;
+    public int totalHarvests = 0; // Track how many times it's been harvested
+    public int maxHarvests = 5; // Field depletes after this many harvests
     public float growthTime = 20f; // Base time to fully grow
     public bool isFullyGrown = false;
-    
+
     [Header("Construction")]
     public bool isUnderConstruction = true;
     public float constructionProgress = 0f;
     public float constructionTime = 8f; // Time for farmer to build the field
-    
+
     [Header("References")]
     public GameObject farmhouse; // The farmhouse that owns this field
     public Villager assignedFarmer; // The farmer working this field
-    
+
     private float growthTimer = 0f;
     private Renderer fieldRenderer;
 
@@ -62,23 +65,23 @@ public class Field : MonoBehaviour
         maxFood = 20 * sizeMultiplier * sizeMultiplier; // Small=20, Medium=80, Large=180
         constructionTime = 5f + (sizeMultiplier * 3f); // Small=8s, Medium=11s, Large=14s
         growthTime = 15f + (sizeMultiplier * 5f); // Small=20s, Medium=25s, Large=30s
-        
+
         // Scale the visual size
         transform.localScale = new Vector3(sizeMultiplier, 0.1f, sizeMultiplier);
-        
+
         Debug.Log($"Field created - Size: {fieldSize}, MaxFood: {maxFood}, ConstructionTime: {constructionTime}s");
     }
 
     public void AdvanceConstruction(float deltaTime)
     {
         if (!isUnderConstruction) return;
-        
+
         constructionProgress += deltaTime;
         if (constructionProgress >= constructionTime)
         {
             CompleteConstruction();
         }
-        
+
         UpdateVisualState();
     }
 
@@ -87,7 +90,7 @@ public class Field : MonoBehaviour
         isUnderConstruction = false;
         constructionProgress = constructionTime;
         currentFood = maxFood / 4; // Start with some food
-        
+
         Debug.Log($"Field construction completed! Starting with {currentFood}/{maxFood} food");
         UpdateVisualState();
     }
@@ -96,38 +99,51 @@ public class Field : MonoBehaviour
     {
         int growthAmount = Random.Range(5, 15);
         currentFood = Mathf.Min(currentFood + growthAmount, maxFood);
-        
+
         if (currentFood >= maxFood)
         {
             isFullyGrown = true;
         }
-        
+
         Debug.Log($"Field grew {growthAmount} food. Now has {currentFood}/{maxFood}");
     }
 
     public int HarvestFood(int requestedAmount)
     {
         if (isUnderConstruction || currentFood <= 0) return 0;
-        
+
         int harvestedAmount = Mathf.Min(requestedAmount, currentFood);
         currentFood -= harvestedAmount;
-        
+
         if (currentFood < maxFood)
         {
             isFullyGrown = false;
             growthTimer = 0f; // Reset growth timer when harvested
+            totalHarvests++;
+        }
+
+        // Check if field is depleted
+        if (totalHarvests >= maxHarvests)
+        {
+            Debug.Log($"🌾 Field depleted after {totalHarvests} harvests. Field will be removed.");
+            if (assignedFarmer != null)
+            {
+                assignedFarmer.targetWorkplace = null;
+            }
+            Destroy(gameObject, 1f); // Destroy after a short delay
+            return harvestedAmount;
         }
-        
-        Debug.Log($"Harvested {harvestedAmount} food from field. Remaining: {currentFood}/{maxFood}");
+
+        Debug.Log($"Harvested {harvestedAmount} food from field. Remaining: {currentFood}/{maxFood}. Uses: {totalHarvests}/{maxHarvests}");
         UpdateVisualState();
-        
+
         return harvestedAmount;
     }
 
     void UpdateVisualState()
     {
         if (fieldRenderer == null) return;
-        
+
         if (isUnderConstruction)
         {
             // Brown/dirt color during construction, with progress indication
@@ -159,11 +175,34 @@ public class Field : MonoBehaviour
         if (isUnderConstruction)
         {
             float progressPercent = (constructionProgress / constructionTime) * 100f;
-            return $"Field ({fieldSize})\nUnder Construction: {progressPercent:F0}%";
+            return $"🌾 Field ({fieldSize})\\nUnder Construction: {progressPercent:F0}%\\nBuilder: {(assignedFarmer != null ? assignedFarmer.villagerName : "Needed")}";
         }
         else
         {
-            return $"Field ({fieldSize})\nFood: {currentFood}/{maxFood}\nGrowth: {isFullyGrown}";
+            float depletionPercent = ((float)totalHarvests / maxHarvests) * 100f;
+            return $"🌾 Field ({fieldSize})\\nFood: {currentFood}/{maxFood}\\nGrown: {(isFullyGrown ? "Yes" : "Growing...")}\\nUses: {totalHarvests}/{maxHarvests} ({depletionPercent:F0}% depleted)";
+        }
+    }
+
+    // ISelectable implementation
+    public void OnSelected()
+    {
+        // Visual indication could be added here
+    }
+
+    public void OnDeselected()
+    {
+        // Clear visual indication
+    }
+
+    void OnMouseDown()
+    {
+        if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
+        {
+            if (GameManager.Instance?.selectionManager != null)
+            {
+                GameManager.Instance.selectionManager.SelectObject(gameObject);
+            }
         }
     }
 

+ 79 - 3
Assets/Scripts/GameUI.cs

@@ -369,6 +369,18 @@ public class GameUI : MonoBehaviour
             return;
         }
 
+        // Check if Builder job requires a Builder's Workshop
+        if (job == JobType.Builder)
+        {
+            GameObject[] workshops = GameObject.FindGameObjectsWithTag("BuildingWorkshop");
+            if (workshops == null || workshops.Length == 0)
+            {
+                Debug.LogWarning("⚠️ Cannot assign Builder job - No Builder's Workshop found! Build one first.");
+                ShowTemporaryMessage("Need Builder's Workshop to train builders!");
+                return;
+            }
+        }
+
         Debug.Log($"Assigning job {job} to stored villager: {currentSelectedVillager.name}");
 
         // Find the closest available workplace for this job
@@ -390,6 +402,29 @@ public class GameUI : MonoBehaviour
         // Update the villager panel to show new job
         UpdateVillagerPanel(currentSelectedVillager);
     }
+
+    void ShowTemporaryMessage(string message)
+    {
+        if (buildModeStatusLabel != null)
+        {
+            buildModeStatusLabel.text = message;
+            buildModeStatusLabel.style.display = DisplayStyle.Flex;
+            buildModeStatusLabel.style.color = Color.yellow;
+        }
+
+        // Clear after 3 seconds
+        StartCoroutine(ClearMessageAfterDelay(3f));
+    }
+
+    System.Collections.IEnumerator ClearMessageAfterDelay(float delay)
+    {
+        yield return new WaitForSeconds(delay);
+        if (buildModeStatusLabel != null)
+        {
+            buildModeStatusLabel.style.display = DisplayStyle.None;
+        }
+    }
+
     void SubscribeToEvents()
     {
         // Subscribe to resource changes
@@ -410,6 +445,9 @@ public class GameUI : MonoBehaviour
         HousingManager.OnHousingStatusChanged += UpdateHousingStatus;
         HousingManager.OnHousingWarning += ShowHousingWarning;
 
+        // Subscribe to selection changes
+        SelectionManager.OnSelectionChanged += OnSelectionChanged;
+
         // Get references to building system components
         buildingSystem = FindFirstObjectByType<BuildingSystem>();
         housingManager = FindFirstObjectByType<HousingManager>();
@@ -606,16 +644,33 @@ public class GameUI : MonoBehaviour
     void UpdateJobButtonStates(Villager selectedVillager)
     {
         bool hasSelection = selectedVillager != null;
+        bool hasBuilderWorkshop = GameObject.FindGameObjectsWithTag("BuildingWorkshop").Length > 0;
 
         // Enable/disable all job buttons based on villager selection
         foreach (var button in jobButtons)
         {
-            button.SetEnabled(hasSelection);
+            string buttonJobName = button.text;
+            bool shouldEnable = hasSelection;
+
+            // Special check for Builder button - requires workshop
+            if (buttonJobName == "Builder")
+            {
+                shouldEnable = hasSelection && hasBuilderWorkshop;
+                if (hasSelection && !hasBuilderWorkshop)
+                {
+                    button.tooltip = "Requires Builder's Workshop";
+                }
+                else
+                {
+                    button.tooltip = "";
+                }
+            }
+
+            button.SetEnabled(shouldEnable);
 
             // Optional: Change button appearance based on villager's current job
             if (hasSelection)
             {
-                string buttonJobName = button.text;
                 string currentJobName = GetJobDisplayName(selectedVillager.currentJob);
 
                 if (buttonJobName == currentJobName)
@@ -663,6 +718,11 @@ public class GameUI : MonoBehaviour
         }
     }
 
+    void OnSelectionChanged()
+    {
+        UpdateSelectionPanel();
+    }
+
     void UpdateSelectionPanel()
     {
         if (selectionInfoLabel == null) return;
@@ -698,7 +758,23 @@ public class GameUI : MonoBehaviour
                 }
                 else
                 {
-                    info = "Selected: " + selectedObject.name;
+                    Field field = selectedObject.GetComponent<Field>();
+                    if (field != null)
+                    {
+                        info = field.GetFieldInfo();
+                    }
+                    else
+                    {
+                        ConstructionSite site = selectedObject.GetComponent<ConstructionSite>();
+                        if (site != null)
+                        {
+                            info = site.GetConstructionInfo();
+                        }
+                        else
+                        {
+                            info = "Selected: " + selectedObject.name;
+                        }
+                    }
                 }
             }
         }

+ 24 - 15
Assets/Scripts/ResourceNode.cs

@@ -62,8 +62,8 @@ public class ResourceNode : MonoBehaviour, ISelectable
 
     void Update()
     {
-        // Regenerate resources over time if not being harvested
-        if (!isBeingHarvested && currentResources < maxResources)
+        // Only farms regenerate - trees and stones are finite
+        if (!isBeingHarvested && currentResources < maxResources && nodeType == ResourceNodeType.Farm)
         {
             float timeSinceLastRegen = Time.time - lastRegenerationTime;
             if (timeSinceLastRegen >= 1f) // Regenerate every second
@@ -73,6 +73,17 @@ public class ResourceNode : MonoBehaviour, ISelectable
                 lastRegenerationTime = Time.time;
             }
         }
+
+        // Destroy depleted resource nodes (except farms)
+        if (currentResources <= 0 && nodeType != ResourceNodeType.Farm)
+        {
+            if (currentHarvester != null)
+            {
+                currentHarvester.targetWorkplace = null; // Clear the workplace reference
+            }
+            Debug.Log($"{nodeType} depleted and removed");
+            Destroy(gameObject);
+        }
     }
 
     public bool StartHarvesting(Villager harvester)
@@ -158,21 +169,19 @@ public class ResourceNode : MonoBehaviour, ISelectable
 
     public string GetNodeInfo()
     {
-        string status = isBeingHarvested ? "Being Harvested" : "Available";
+        string icon = nodeType switch
+        {
+            ResourceNodeType.Tree => "🌲",
+            ResourceNodeType.Stone => "🪨",
+            ResourceNodeType.Farm => "🌾",
+            _ => "📦"
+        };
+
+        string status = isBeingHarvested ? "⚙️ Being Harvested" : "✓ Available";
         if (currentHarvester != null)
             status += $" by {currentHarvester.villagerName}";
 
-        return $"{nodeType} Node\nResources: {currentResources}/{maxResources}\nStatus: {status}";
-    }
-
-    void OnMouseDown()
-    {
-        if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
-        {
-            if (GameManager.Instance?.selectionManager != null)
-            {
-                GameManager.Instance.selectionManager.SelectObject(gameObject);
-            }
-        }
+        float percentage = (float)currentResources / maxResources * 100f;
+        return $"{icon} {nodeType}\nResources: {currentResources}/{maxResources} ({percentage:F0}%)\n{status}";
     }
 }

+ 91 - 27
Assets/Scripts/SceneSetup.cs

@@ -142,16 +142,33 @@ public class SceneSetup : MonoBehaviour
         // Create Trees in forest-like clusters
         CreateForests();
 
-        // Create Stones
-        for (int i = 0; i < numberOfStones; i++)
+        // Create Stones in clusters
+        int numStoneClusters = Random.Range(2, 4); // 2-3 stone clusters
+
+        for (int cluster = 0; cluster < numStoneClusters; cluster++)
         {
-            Vector3 position = GetRandomPosition();
-            CreateStone(position, i);
+            Vector3 clusterCenter = GetRandomPosition();
+
+            // Create 3-5 stones in this cluster
+            int stonesInCluster = Random.Range(3, 6);
+
+            for (int i = 0; i < stonesInCluster; i++)
+            {
+                Vector3 offset = Random.insideUnitSphere * 3f; // 3 unit radius for tighter clusters
+                offset.y = 0;
+
+                Vector3 stonePosition = clusterCenter + offset;
+                stonePosition.x = Mathf.Clamp(stonePosition.x, -resourceSpawnRadius + 2, resourceSpawnRadius - 2);
+                stonePosition.z = Mathf.Clamp(stonePosition.z, -resourceSpawnRadius + 2, resourceSpawnRadius - 2);
+
+                CreateStone(stonePosition, cluster * 10 + i);
+            }
         }
 
+        Debug.Log($"Created {numStoneClusters} stone clusters");
+
         // No longer create pre-made farms - farmhouses will be built by players
     }
-
     void CreateTree(Vector3 position, int index)
     {
         GameObject tree = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
@@ -164,9 +181,10 @@ public class SceneSetup : MonoBehaviour
         ResourceNode node = tree.AddComponent<ResourceNode>();
         node.nodeType = ResourceNodeType.Tree;
         node.resourceType = ResourceType.Wood;
-        node.maxResources = 50;
-        node.currentResources = 50;
-        node.regenerationRate = 2f;
+        node.maxResources = Random.Range(40, 70); // Variable wood amounts
+        node.currentResources = node.maxResources;
+        node.regenerationRate = 0f; // Trees don't regenerate
+        node.nodeRenderer = tree.GetComponent<Renderer>();
 
         // Apply material
         if (treeMaterial != null)
@@ -186,34 +204,80 @@ public class SceneSetup : MonoBehaviour
 
     void CreateStone(Vector3 position, int index)
     {
-        GameObject stone = GameObject.CreatePrimitive(PrimitiveType.Sphere);
-        stone.name = $"Stone_{index + 1}";
-        stone.tag = "Stone";
-        stone.transform.position = position;
-        stone.transform.localScale = Vector3.one * 1.5f;
+        // Create stone cluster with multiple rocks
+        GameObject stoneCluster = new GameObject($"StoneCluster_{index + 1}");
+        stoneCluster.tag = "Stone";
+        stoneCluster.transform.position = position;
+
+        // Main large stone with random size and position jitter
+        GameObject mainStone = GameObject.CreatePrimitive(PrimitiveType.Sphere);
+        mainStone.name = "MainStone";
+        mainStone.transform.SetParent(stoneCluster.transform);
+        mainStone.transform.localPosition = new Vector3(
+            Random.Range(-0.2f, 0.2f),
+            Random.Range(-0.1f, 0.1f),
+            Random.Range(-0.2f, 0.2f)
+        );
+        mainStone.transform.localScale = Vector3.one * Random.Range(1.3f, 1.8f);
+        mainStone.transform.rotation = Random.rotation;
+
+        // Add 2-5 smaller stones with more varied positioning
+        int smallStones = Random.Range(2, 6);
+        for (int i = 0; i < smallStones; i++)
+        {
+            GameObject smallStone = GameObject.CreatePrimitive(PrimitiveType.Sphere);
+            smallStone.name = $"SmallStone_{i}";
+            smallStone.transform.SetParent(stoneCluster.transform);
+
+            // More random angle distribution instead of even spacing
+            float angle = Random.Range(0f, 360f);
+            float distance = Random.Range(0.6f, 1.4f);
+            Vector3 offset = new Vector3(
+                Mathf.Cos(angle * Mathf.Deg2Rad) * distance,
+                Random.Range(-0.3f, 0.2f),
+                Mathf.Sin(angle * Mathf.Deg2Rad) * distance
+            );
+
+            smallStone.transform.localPosition = offset;
+            smallStone.transform.localScale = Vector3.one * Random.Range(0.5f, 1.1f);
+            smallStone.transform.rotation = Random.rotation;
+
+            // Remove collider so only parent cluster is selectable
+            Collider smallCollider = smallStone.GetComponent<Collider>();
+            if (smallCollider != null)
+                Destroy(smallCollider);
+
+            Renderer smallRenderer = smallStone.GetComponent<Renderer>();
+            if (stoneMaterial != null)
+                smallRenderer.material = stoneMaterial;
+            else
+                smallRenderer.material.color = Color.gray;
+        }
 
-        // Add ResourceNode component
-        ResourceNode node = stone.AddComponent<ResourceNode>();
+        // Add ResourceNode component to parent
+        ResourceNode node = stoneCluster.AddComponent<ResourceNode>();
         node.nodeType = ResourceNodeType.Stone;
         node.resourceType = ResourceType.Stone;
-        node.maxResources = 75;
-        node.currentResources = 75;
-        node.regenerationRate = 0.5f;
+        node.maxResources = Random.Range(60, 100); // Variable stone amounts
+        node.currentResources = node.maxResources;
+        node.regenerationRate = 0f; // Stones don't regenerate
+        node.nodeRenderer = mainStone.GetComponent<Renderer>();
 
-        // Apply material
+        // Set material
         if (stoneMaterial != null)
-        {
-            stone.GetComponent<Renderer>().material = stoneMaterial;
-        }
+            node.nodeRenderer.material = stoneMaterial;
         else
-        {
-            stone.GetComponent<Renderer>().material.color = Color.gray;
-        }
+            node.nodeRenderer.material.color = Color.gray;
+
+        // Add collider to parent for clicking
+        BoxCollider clusterCollider = stoneCluster.AddComponent<BoxCollider>();
+        clusterCollider.size = new Vector3(3f, 2f, 3f);
+        clusterCollider.center = Vector3.up * 0.5f;
 
         // Create selection indicator
-        CreateSelectionIndicator(stone, node);
+        CreateSelectionIndicator(stoneCluster, node);
 
-        Debug.Log($"Created Stone at {position}");
+        Debug.Log($"Created Stone Cluster at {position} with {node.maxResources} stone");
     }
 
     void CreateFarm(Vector3 position, int index)

+ 137 - 2
Assets/Scripts/SelectionManager.cs

@@ -17,9 +17,17 @@ public class SelectionManager : MonoBehaviour
     private GameObject dragGhost;
     private Vector3 dragStartPosition;
 
+    // Box Selection
+    private bool isBoxSelecting = false;
+    private Vector2 boxSelectionStart;
+
     public Villager SelectedVillager => selectedVillager;
     public GameObject SelectedObject => selectedObject;
 
+    // Event for selection changes
+    public delegate void SelectionChangedHandler();
+    public static event SelectionChangedHandler OnSelectionChanged;
+
     void Start()
     {
         playerCamera = Camera.main;
@@ -35,11 +43,40 @@ public class SelectionManager : MonoBehaviour
 
     void HandleInput()
     {
-        // Left click - selection
+        // Left click - selection or box selection start
         var mouse = Mouse.current;
         if (mouse.leftButton.wasPressedThisFrame)
         {
-            HandleSelection();
+            // Start potential box selection
+            boxSelectionStart = mouse.position.ReadValue();
+            isBoxSelecting = false; // Not yet, wait for drag
+        }
+
+        // Check if dragging for box selection (only when no villager is selected)
+        if (mouse.leftButton.isPressed && !isDragging && selectedVillager == null)
+        {
+            Vector2 currentMousePos = mouse.position.ReadValue();
+            float dragDistance = Vector2.Distance(boxSelectionStart, currentMousePos);
+
+            // Start box selection if dragged more than 10 pixels
+            if (dragDistance > 10f && !isBoxSelecting)
+            {
+                isBoxSelecting = true;
+                Debug.Log("Started box selection");
+            }
+        }        // Complete box selection on release
+        if (mouse.leftButton.wasReleasedThisFrame)
+        {
+            if (isBoxSelecting)
+            {
+                CompleteBoxSelection();
+                isBoxSelecting = false;
+            }
+            else if (!isDragging)
+            {
+                // Single click selection (only if not dragging)
+                HandleSelection();
+            }
         }
 
         // Right click - cancel/deselect
@@ -108,6 +145,9 @@ public class SelectionManager : MonoBehaviour
 
         var mouse = Mouse.current;
 
+        // Don't start dragging if box selecting
+        if (isBoxSelecting) return;
+
         // Start dragging
         if (selectedVillager != null && mouse.leftButton.wasPressedThisFrame && !isDragging)
         {
@@ -226,6 +266,17 @@ public class SelectionManager : MonoBehaviour
             _ => selectedVillager.currentJob // Keep current job if dropped on something else
         };
 
+        // Special check for Builder job - requires workshop
+        if (newJob == JobType.Builder)
+        {
+            GameObject[] workshops = GameObject.FindGameObjectsWithTag("BuildingWorkshop");
+            if (workshops == null || workshops.Length == 0)
+            {
+                Debug.LogWarning("⚠️ Cannot assign Builder job - No Builder's Workshop found! Build one first.");
+                return;
+            }
+        }
+
         if (newJob != selectedVillager.currentJob || (newJob != JobType.None && selectedVillager.targetWorkplace != dropTarget))
         {
             // Assign job and specific workplace
@@ -245,6 +296,9 @@ public class SelectionManager : MonoBehaviour
 
         Debug.Log($"SelectionManager: Selected villager: {villager.villagerName}");
         Debug.Log($"SelectionManager: OnVillagerSelected event triggered");
+
+        // Notify UI of selection change
+        OnSelectionChanged?.Invoke();
     }
 
     public void SelectObject(GameObject obj)
@@ -258,6 +312,9 @@ public class SelectionManager : MonoBehaviour
         selectable?.OnSelected();
 
         Debug.Log($"Selected object: {obj.name}");
+
+        // Notify UI of selection change
+        OnSelectionChanged?.Invoke();
     }
 
     public void DeselectAll()
@@ -281,6 +338,80 @@ public class SelectionManager : MonoBehaviour
             isDragging = false;
             DestroyDragGhost();
         }
+
+        Debug.Log("SelectionManager: Deselected all");
+
+        // Notify UI of selection change
+        OnSelectionChanged?.Invoke();
+    }
+
+    void OnGUI()
+    {
+        if (isBoxSelecting && Mouse.current != null)
+        {
+            Vector2 mouseStart = boxSelectionStart;
+            Vector2 mouseEnd = Mouse.current.position.ReadValue();
+
+            // Convert to GUI coordinates (Y is flipped)
+            mouseStart.y = Screen.height - mouseStart.y;
+            mouseEnd.y = Screen.height - mouseEnd.y;
+
+            Rect selectionRect = new Rect(
+                Mathf.Min(mouseStart.x, mouseEnd.x),
+                Mathf.Min(mouseStart.y, mouseEnd.y),
+                Mathf.Abs(mouseStart.x - mouseEnd.x),
+                Mathf.Abs(mouseStart.y - mouseEnd.y)
+            );
+
+            // Draw selection box
+            GUI.color = new Color(0.8f, 0.8f, 0.95f, 0.25f);
+            GUI.DrawTexture(selectionRect, Texture2D.whiteTexture);
+            GUI.color = new Color(0.8f, 0.8f, 0.95f, 1f);
+            GUI.Box(selectionRect, "");
+        }
+    }
+
+    void CompleteBoxSelection()
+    {
+        Vector2 mouseStart = boxSelectionStart;
+        Vector2 mouseEnd = Mouse.current.position.ReadValue();
+
+        // Create screen space rectangle
+        Rect selectionRect = new Rect(
+            Mathf.Min(mouseStart.x, mouseEnd.x),
+            Mathf.Min(mouseStart.y, mouseEnd.y),
+            Mathf.Abs(mouseStart.x - mouseEnd.x),
+            Mathf.Abs(mouseStart.y - mouseEnd.y)
+        );
+
+        // Find all villagers
+        Villager[] allVillagers = FindObjectsOfType<Villager>();
+        Villager firstVillager = null;
+
+        foreach (Villager villager in allVillagers)
+        {
+            Vector3 screenPos = playerCamera.WorldToScreenPoint(villager.transform.position);
+
+            // Check if villager is in selection box and in front of camera
+            if (screenPos.z > 0 && selectionRect.Contains(new Vector2(screenPos.x, screenPos.y)))
+            {
+                if (firstVillager == null)
+                {
+                    firstVillager = villager;
+                }
+            }
+        }
+
+        // Select the first villager found
+        if (firstVillager != null)
+        {
+            SelectVillager(firstVillager);
+            Debug.Log($"Box selection completed: selected {firstVillager.villagerName}");
+        }
+        else
+        {
+            Debug.Log("Box selection completed: no villagers found");
+        }
     }
 
     void CancelCurrentAction()
@@ -290,6 +421,10 @@ public class SelectionManager : MonoBehaviour
             isDragging = false;
             DestroyDragGhost();
         }
+        else if (isBoxSelecting)
+        {
+            isBoxSelecting = false;
+        }
         else
         {
             DeselectAll();

+ 106 - 8
Assets/Scripts/Villager.cs

@@ -179,6 +179,16 @@ public class Villager : MonoBehaviour
         {
             state = VillagerState.Working;
             workTimer = 0f;
+
+            // Start harvesting on the resource node
+            if (targetWorkplace != null)
+            {
+                ResourceNode node = targetWorkplace.GetComponent<ResourceNode>();
+                if (node != null)
+                {
+                    node.StartHarvesting(this);
+                }
+            }
         }
     }
 
@@ -195,10 +205,36 @@ public class Villager : MonoBehaviour
         float workDuration = GetWorkDuration();
         if (workTimer >= workDuration)
         {
-            CompleteWork();
+            // Actually harvest resources from the node
+            ResourceNode node = targetWorkplace.GetComponent<ResourceNode>();
+            if (node != null)
+            {
+                int requestedAmount = GetProducedAmount();
+                int harvestedAmount = node.HarvestResources(requestedAmount, GetWorkEfficiency());
+                carryingAmount = harvestedAmount;
+                carryingResource = node.resourceType;
+
+                if (harvestedAmount > 0)
+                {
+                    // Stop harvesting before leaving
+                    node.StopHarvesting();
+                    CompleteWork();
+                }
+                else
+                {
+                    // No resources left, stop harvesting and find new workplace
+                    node.StopHarvesting();
+                    targetWorkplace = null;
+                    state = VillagerState.Idle;
+                }
+            }
+            else
+            {
+                // Fallback for non-node workplaces
+                CompleteWork();
+            }
         }
     }
-
     void HandleMovingToDeliver()
     {
         if (MoveToTarget(targetPosition))
@@ -246,6 +282,26 @@ public class Villager : MonoBehaviour
             return;
         }
 
+        // Farmers should check if they need to plant a field
+        if (currentJob == JobType.Farmer && homeBuilding != null)
+        {
+            // Check if there are fewer than 2 fields near the farmhouse
+            Field[] nearbyFields = FindObjectsOfType<Field>();
+            int fieldsNearHome = 0;
+            foreach (Field field in nearbyFields)
+            {
+                if (field.farmhouse == homeBuilding)
+                    fieldsNearHome++;
+            }
+
+            // Plant a new field if needed
+            if (fieldsNearHome < 2)
+            {
+                PlantNewField();
+                return;
+            }
+        }
+
         // If villager already has a specific workplace assigned, use it
         if (targetWorkplace != null)
         {
@@ -278,11 +334,15 @@ public class Villager : MonoBehaviour
 
     void CompleteWork()
     {
-        ResourceType producedResource = GetProducedResource();
-        int amount = GetProducedAmount();
-
-        carryingResource = producedResource;
-        carryingAmount = amount;
+        // carryingResource and carryingAmount are already set by HandleWorking if harvesting from a node
+        // Only set them here if not already set (for jobs that don't use ResourceNode)
+        if (carryingAmount == 0)
+        {
+            ResourceType producedResource = GetProducedResource();
+            int amount = GetProducedAmount();
+            carryingResource = producedResource;
+            carryingAmount = amount;
+        }
 
         // Add experience
         experience.AddExperience(currentJob, 0.1f);
@@ -510,7 +570,17 @@ public class Villager : MonoBehaviour
             {
                 Debug.Log($"{villagerName} completed construction of {assignedConstructionSite.buildingName}");
                 assignedConstructionSite = null;
-                state = VillagerState.Idle;
+
+                // Return to builder's workshop
+                if (targetWorkplace != null)
+                {
+                    targetPosition = targetWorkplace.transform.position;
+                    state = VillagerState.MovingToWork;
+                }
+                else
+                {
+                    state = VillagerState.Idle;
+                }
             }
         }
     }
@@ -545,4 +615,32 @@ public class Villager : MonoBehaviour
             }
         }
     }
+
+    void PlantNewField()
+    {
+        if (homeBuilding == null) return;
+
+        // Find a position near the farmhouse to plant a field
+        Vector3 farmhousePos = homeBuilding.transform.position;
+        Vector2 randomCircle = UnityEngine.Random.insideUnitCircle * 8f; // 8 units away
+        Vector3 fieldPosition = farmhousePos + new Vector3(randomCircle.x, 0, randomCircle.y);
+        fieldPosition.y = 0.1f; // Slightly above ground
+
+        // Create the field
+        GameObject fieldObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
+        fieldObj.name = $"Field_{homeBuilding.name}";
+        fieldObj.tag = "Farm";
+        fieldObj.transform.position = fieldPosition;
+
+        Field field = fieldObj.AddComponent<Field>();
+        field.farmhouse = homeBuilding;
+        field.fieldSize = FieldSize.Small;
+        field.assignedFarmer = this;
+
+        // Assign this field to the farmer to build
+        assignedField = field;
+        state = VillagerState.BuildingField;
+
+        Debug.Log($"{villagerName} started planting a new field near {homeBuilding.name}");
+    }
 }

+ 4 - 0
Logs/shadercompiler-UnityShaderCompiler.exe-0.log

@@ -1 +1,5 @@
 Base path: 'C:/Program Files/Unity/Hub/Editor/6000.2.10f1/Editor/Data', plugins path 'C:/Program Files/Unity/Hub/Editor/6000.2.10f1/Editor/Data/PlaybackEngines'
+Cmd: initializeCompiler
+
+Cmd: initializeCompiler
+

+ 16 - 16
UserSettings/Layouts/default-6000.dwlt

@@ -19,7 +19,7 @@ MonoBehaviour:
     width: 3440
     height: 1349
   m_ShowMode: 4
-  m_Title: Console
+  m_Title: Game
   m_RootView: {fileID: 5}
   m_MinSize: {x: 875, y: 332}
   m_MaxSize: {x: 10000, y: 10000}
@@ -74,7 +74,7 @@ MonoBehaviour:
   m_MinSize: {x: 200, y: 50}
   m_MaxSize: {x: 16192, y: 8096}
   vertical: 0
-  controlID: 117
+  controlID: 119
   draggingID: 0
 --- !u!114 &4
 MonoBehaviour:
@@ -198,7 +198,7 @@ MonoBehaviour:
   m_MinSize: {x: 400, y: 100}
   m_MaxSize: {x: 32384, y: 16192}
   vertical: 0
-  controlID: 146
+  controlID: 148
   draggingID: 0
 --- !u!114 &9
 MonoBehaviour:
@@ -224,7 +224,7 @@ MonoBehaviour:
   m_MinSize: {x: 300, y: 100}
   m_MaxSize: {x: 24288, y: 16192}
   vertical: 1
-  controlID: 116
+  controlID: 48
   draggingID: 0
 --- !u!114 &10
 MonoBehaviour:
@@ -534,7 +534,7 @@ MonoBehaviour:
     m_OverlaysVisible: 1
   m_LockTracker:
     m_IsLocked: 0
-  m_LastSelectedObjectID: -19770
+  m_LastSelectedObjectID: -45066
 --- !u!114 &18
 MonoBehaviour:
   m_ObjectHideFlags: 52
@@ -1208,9 +1208,9 @@ MonoBehaviour:
   m_AudioPlay: 0
   m_DebugDrawModesUseInteractiveLightBakingData: 0
   m_Position:
-    m_Target: {x: -0.8965654, y: 0.026461218, z: 0.87804085}
+    m_Target: {x: -0.734545, y: 0, z: 0.029852048}
     speed: 2
-    m_Value: {x: -0.8965654, y: 0.026461218, z: 0.87804085}
+    m_Value: {x: -0.734545, y: 0, z: 0.029852048}
   m_RenderMode: 0
   m_CameraMode:
     drawMode: 0
@@ -1260,9 +1260,9 @@ MonoBehaviour:
     speed: 2
     m_Value: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226}
   m_Size:
-    m_Target: 4.3548284
+    m_Target: 2.170488
     speed: 2
-    m_Value: 4.3548284
+    m_Value: 2.170488
   m_Ortho:
     m_Target: 0
     speed: 2
@@ -1396,7 +1396,7 @@ MonoBehaviour:
     m_SkipHidden: 0
     m_SearchArea: 1
     m_Folders:
-    - Assets/Scripts
+    - Assets
     m_Globs: []
     m_ProductIds: 
     m_AnyWithAssetOrigin: 0
@@ -1406,16 +1406,16 @@ MonoBehaviour:
   m_ViewMode: 1
   m_StartGridSize: 67
   m_LastFolders:
-  - Assets/Scripts
+  - Assets
   m_LastFoldersGridSize: 67
   m_LastProjectPath: C:\Users\Axel-PC\GathererOfSouls
   m_LockTracker:
     m_IsLocked: 0
   m_FolderTreeState:
     scrollPos: {x: 0, y: 0}
-    m_SelectedIDs: 66ad0000
-    m_LastClickedID: 44390
-    m_ExpandedIDs: 0000000032e7000034e7000036e70000
+    m_SelectedIDs: 30ac0000
+    m_LastClickedID: 44080
+    m_ExpandedIDs: 0000000030ac000032ac000034ac0000
     m_RenameOverlay:
       m_UserAcceptedRename: 0
       m_Name: 
@@ -1444,7 +1444,7 @@ MonoBehaviour:
     scrollPos: {x: 0, y: 0}
     m_SelectedIDs: 
     m_LastClickedID: 0
-    m_ExpandedIDs: 0000000032e7000034e7000036e70000
+    m_ExpandedIDs: 0000000030ac000032ac000034ac0000
     m_RenameOverlay:
       m_UserAcceptedRename: 0
       m_Name: 
@@ -1472,7 +1472,7 @@ MonoBehaviour:
   m_ListAreaState:
     m_SelectedInstanceIDs: 
     m_LastClickedInstanceID: 0
-    m_HadKeyboardFocusLastEvent: 1
+    m_HadKeyboardFocusLastEvent: 0
     m_ExpandedInstanceIDs: c6230000040a0100d8ce000056ae000054e0000044bd00004eb500003cb1000000000000
     m_RenameOverlay:
       m_UserAcceptedRename: 0