| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- using UnityEngine;
- using UnityEngine.InputSystem;
- using System.Collections.Generic;
- using System;
- [System.Serializable]
- public enum JobType
- {
- None, // Unemployed - transports goods
- Woodcutter, // Cuts trees
- Stonecutter, // Mines stone
- Farmer, // Grows food
- Builder // Constructs buildings
- }
- [System.Serializable]
- public enum VillagerState
- {
- Idle,
- MovingToWork,
- Working,
- MovingToDeliver,
- Delivering,
- Transporting
- }
- [System.Serializable]
- public class Experience
- {
- public float woodcutting = 1f;
- public float stonecutting = 1f;
- public float farming = 1f;
- public float building = 1f;
- public float GetExperienceForJob(JobType job)
- {
- return job switch
- {
- JobType.Woodcutter => woodcutting,
- JobType.Stonecutter => stonecutting,
- JobType.Farmer => farming,
- JobType.Builder => building,
- _ => 1f
- };
- }
- public void AddExperience(JobType job, float amount)
- {
- switch (job)
- {
- case JobType.Woodcutter:
- woodcutting += amount;
- break;
- case JobType.Stonecutter:
- stonecutting += amount;
- break;
- case JobType.Farmer:
- farming += amount;
- break;
- case JobType.Builder:
- building += amount;
- break;
- }
- }
- }
- public class Villager : MonoBehaviour
- {
- [Header("Villager Info")]
- public string villagerName;
- public JobType currentJob = JobType.None;
- public VillagerState state = VillagerState.Idle;
- [Header("Experience")]
- public Experience experience = new Experience();
- [Header("Work Settings")]
- public float workSpeed = 1f;
- public float moveSpeed = 3f;
- public float workRange = 2f;
- [Header("Current Task")]
- public GameObject targetWorkplace;
- public GameObject targetDelivery;
- public ResourceType carryingResource;
- public int carryingAmount = 0;
- public int maxCarryCapacity = 10;
- [Header("Visual")]
- public Renderer villagerRenderer;
- public GameObject selectionIndicator;
- private Vector3 targetPosition;
- private bool isSelected = false;
- private float workTimer = 0f;
- private VillagerManager villagerManager;
- public static event Action<Villager> OnVillagerSelected;
- public static event Action<Villager, JobType> OnJobChanged;
- void Start()
- {
- villagerManager = FindObjectOfType<VillagerManager>();
- if (villagerRenderer == null)
- villagerRenderer = GetComponent<Renderer>();
- if (selectionIndicator != null)
- selectionIndicator.SetActive(false);
- // Random starting experience
- experience.woodcutting = UnityEngine.Random.Range(0.8f, 1.5f);
- experience.stonecutting = UnityEngine.Random.Range(0.8f, 1.5f);
- experience.farming = UnityEngine.Random.Range(0.8f, 1.5f);
- experience.building = UnityEngine.Random.Range(0.8f, 1.5f);
- }
- void Update()
- {
- UpdateBehavior();
- }
- void UpdateBehavior()
- {
- switch (state)
- {
- case VillagerState.Idle:
- HandleIdleState();
- break;
- case VillagerState.MovingToWork:
- HandleMovingToWork();
- break;
- case VillagerState.Working:
- HandleWorking();
- break;
- case VillagerState.MovingToDeliver:
- HandleMovingToDeliver();
- break;
- case VillagerState.Delivering:
- HandleDelivering();
- break;
- case VillagerState.Transporting:
- HandleTransporting();
- break;
- }
- }
- void HandleIdleState()
- {
- if (currentJob == JobType.None)
- {
- // Unemployed villagers stay idle until assigned a job
- // They can be selected and assigned jobs via drag-and-drop
- return;
- }
- else
- {
- // Look for work appropriate to job
- FindWork();
- }
- }
- void HandleMovingToWork()
- {
- if (MoveToTarget(targetPosition))
- {
- state = VillagerState.Working;
- workTimer = 0f;
- }
- }
- void HandleWorking()
- {
- if (targetWorkplace == null)
- {
- state = VillagerState.Idle;
- return;
- }
- workTimer += Time.deltaTime * GetWorkEfficiency();
- float workDuration = GetWorkDuration();
- if (workTimer >= workDuration)
- {
- CompleteWork();
- }
- }
- void HandleMovingToDeliver()
- {
- if (MoveToTarget(targetPosition))
- {
- state = VillagerState.Delivering;
- }
- }
- void HandleDelivering()
- {
- DeliverResources();
- state = VillagerState.Idle;
- }
- void HandleTransporting()
- {
- // Similar to delivering but for transport tasks
- if (MoveToTarget(targetPosition))
- {
- DeliverResources();
- state = VillagerState.Idle;
- }
- }
- bool MoveToTarget(Vector3 target)
- {
- Vector3 direction = (target - transform.position).normalized;
- transform.position += direction * moveSpeed * Time.deltaTime;
- return Vector3.Distance(transform.position, target) < 0.5f;
- }
- void FindWork()
- {
- // If villager already has a specific workplace assigned, use it
- if (targetWorkplace != null)
- {
- targetPosition = targetWorkplace.transform.position;
- state = VillagerState.MovingToWork;
- return;
- }
- // Otherwise, find appropriate workplace based on job
- GameObject workplace = villagerManager.FindWorkplaceForJob(currentJob, transform.position);
- if (workplace != null)
- {
- targetWorkplace = workplace;
- targetPosition = workplace.transform.position;
- state = VillagerState.MovingToWork;
- }
- }
- void FindTransportTask()
- {
- // Look for resources that need to be moved
- // This is simplified - in a real game you'd have a more complex task system
- var townHall = GameObject.FindWithTag("TownHall");
- if (townHall != null && carryingAmount == 0)
- {
- // Simple transport: move to a random resource and bring it to town hall
- state = VillagerState.Transporting;
- }
- }
- void CompleteWork()
- {
- ResourceType producedResource = GetProducedResource();
- int amount = GetProducedAmount();
- carryingResource = producedResource;
- carryingAmount = amount;
- // Add experience
- experience.AddExperience(currentJob, 0.1f);
- // Find delivery target (usually TownHall)
- GameObject townHall = GameObject.FindWithTag("TownHall");
- if (townHall != null)
- {
- targetDelivery = townHall;
- targetPosition = townHall.transform.position;
- state = VillagerState.MovingToDeliver;
- }
- else
- {
- // Deliver immediately if no town hall found
- DeliverResources();
- state = VillagerState.Idle;
- }
- }
- void DeliverResources()
- {
- if (carryingAmount > 0)
- {
- Debug.Log($"{villagerName} delivering {carryingAmount} {carryingResource} to storage");
- GameManager.Instance.resourceManager.AddResource(carryingResource, carryingAmount);
- carryingAmount = 0;
- }
- }
- ResourceType GetProducedResource()
- {
- return currentJob switch
- {
- JobType.Woodcutter => ResourceType.Wood,
- JobType.Stonecutter => ResourceType.Stone,
- JobType.Farmer => ResourceType.Food,
- _ => ResourceType.Wood
- };
- }
- int GetProducedAmount()
- {
- float efficiency = GetWorkEfficiency();
- return Mathf.RoundToInt(UnityEngine.Random.Range(1, 4) * efficiency);
- }
- float GetWorkEfficiency()
- {
- return experience.GetExperienceForJob(currentJob) * workSpeed;
- }
- float GetWorkDuration()
- {
- return 3f / GetWorkEfficiency(); // Base 3 seconds, modified by efficiency
- }
- public void SetJob(JobType newJob)
- {
- currentJob = newJob;
- state = VillagerState.Idle;
- // Clear previous workplace assignment when changing jobs
- if (currentJob == JobType.None)
- {
- targetWorkplace = null;
- }
- OnJobChanged?.Invoke(this, newJob);
- // Update visual appearance based on job
- UpdateAppearance();
- }
- public void AssignToSpecificWorkplace(GameObject workplace)
- {
- targetWorkplace = workplace;
- if (workplace != null)
- {
- targetPosition = workplace.transform.position;
- state = VillagerState.MovingToWork;
- Debug.Log($"{villagerName} assigned to specific workplace: {workplace.name}");
- }
- }
- void UpdateAppearance()
- {
- if (villagerRenderer != null)
- {
- Color jobColor = currentJob switch
- {
- JobType.Woodcutter => Color.green,
- JobType.Stonecutter => Color.gray,
- JobType.Farmer => Color.yellow,
- JobType.Builder => Color.blue,
- _ => Color.white
- };
- villagerRenderer.material.color = jobColor;
- }
- }
- public void SetSelected(bool selected)
- {
- isSelected = selected;
- if (selectionIndicator != null)
- selectionIndicator.SetActive(selected);
- Debug.Log($"Villager {villagerName} SetSelected: {selected}");
- if (selected)
- {
- Debug.Log($"Villager {villagerName} triggering OnVillagerSelected event");
- OnVillagerSelected?.Invoke(this);
- }
- }
- void OnMouseDown()
- {
- // Use Physics raycast instead of OnMouseDown for better reliability
- if (Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame)
- {
- if (GameManager.Instance?.selectionManager != null)
- {
- GameManager.Instance.selectionManager.SelectVillager(this);
- }
- }
- }
- public string GetStatusText()
- {
- string status = $"{villagerName}\nJob: {currentJob}\nState: {state}";
- if (carryingAmount > 0)
- status += $"\nCarrying: {carryingAmount} {carryingResource}";
- if (currentJob == JobType.None)
- status += "\n[Click and drag to assign job]";
- return status;
- }
- }
|