using UnityEngine; /// /// Individual quest marker component that displays quest information and handles interactions /// public class QuestMarker : MonoBehaviour { [Header("Marker Components")] [SerializeField] private ActiveQuest activeQuest; [SerializeField] private GameObject completionArea; [Header("Visual Settings")] [SerializeField] private bool showFloatingText = true; [SerializeField] private float bobSpeed = 1f; [SerializeField] private float bobHeight = 0.5f; private Vector3 originalPosition; private Renderer markerRenderer; private TextMesh floatingText; private float time = 0f; public ActiveQuest ActiveQuest => activeQuest; private void Start() { originalPosition = transform.position; markerRenderer = GetComponent(); if (showFloatingText) { CreateFloatingText(); } } private void Update() { // Gentle bobbing animation if (bobHeight > 0f) { time += Time.deltaTime * bobSpeed; float newY = originalPosition.y + Mathf.Sin(time) * bobHeight; transform.position = new Vector3(originalPosition.x, newY, originalPosition.z); } // Update floating text if quest exists if (activeQuest != null && floatingText != null) { UpdateFloatingText(); } } /// /// Initialize the quest marker with quest data /// public void Initialize(ActiveQuest quest, GameObject area = null) { activeQuest = quest; completionArea = area; if (completionArea != null) { completionArea.transform.SetParent(transform); } // Update visual representation UpdateMarkerVisuals(); } /// /// Set the marker color /// public void SetColor(Color color) { if (markerRenderer != null) { markerRenderer.material.color = color; } // Also color the completion area if it exists if (completionArea != null) { var areaRenderer = completionArea.GetComponent(); if (areaRenderer != null) { var areaColor = color; areaColor.a = 0.3f; // Make area semi-transparent areaRenderer.material.color = areaColor; } } } private void CreateFloatingText() { // Create floating text object GameObject textObject = new GameObject("QuestText"); textObject.transform.SetParent(transform); textObject.transform.localPosition = Vector3.up * 1.5f; // Add TextMesh component floatingText = textObject.AddComponent(); floatingText.anchor = TextAnchor.MiddleCenter; floatingText.alignment = TextAlignment.Center; floatingText.fontSize = 16; floatingText.color = Color.white; // Make text face camera (simple billboard) textObject.transform.LookAt(Camera.main?.transform ?? Camera.current?.transform); textObject.transform.Rotate(0, 180, 0); // Flip to face camera correctly } private void UpdateFloatingText() { if (floatingText == null || activeQuest?.questData == null) return; // Show quest title and time remaining string questText = activeQuest.questData.questTitle; // Add time remaining with color coding var urgency = activeQuest.GetUrgency(); string timeRemaining = activeQuest.GetTimeRemainingString(); // Color code based on urgency string timeColor = urgency switch { QuestUrgency.Low => "white", QuestUrgency.Medium => "yellow", QuestUrgency.High => "orange", QuestUrgency.Critical => "red", _ => "white" }; floatingText.text = $"{questText}\n{timeRemaining}"; // Make text face camera if (Camera.main != null) { Vector3 directionToCamera = Camera.main.transform.position - floatingText.transform.position; floatingText.transform.rotation = Quaternion.LookRotation(-directionToCamera); } } private void UpdateMarkerVisuals() { if (activeQuest?.questData == null) return; // Scale marker based on quest importance/difficulty float scale = activeQuest.questData.difficulty switch { QuestDifficulty.Easy => 0.8f, QuestDifficulty.Normal => 1.0f, QuestDifficulty.Hard => 1.2f, QuestDifficulty.Legendary => 1.5f, _ => 1.0f }; transform.localScale = Vector3.one * scale; // Adjust bob speed based on urgency var urgency = activeQuest.GetUrgency(); bobSpeed = urgency switch { QuestUrgency.Low => 0.5f, QuestUrgency.Medium => 1.0f, QuestUrgency.High => 1.5f, QuestUrgency.Critical => 2.5f, _ => 1.0f }; } /// /// Called when player clicks on the quest marker /// private void OnMouseDown() { if (activeQuest?.questData == null) return; // Show quest info in UI or console ShowQuestInfo(); } private void ShowQuestInfo() { if (activeQuest?.questData == null) return; var quest = activeQuest.questData; string info = $"Quest: {quest.questTitle}\n" + $"Description: {quest.questDescription}\n" + $"Time Remaining: {activeQuest.GetTimeRemainingString()}\n" + $"Progress: {activeQuest.GetOverallProgress() * 100:F0}%\n" + $"Reward: {quest.goldReward}g, {quest.renownReward} renown"; // TODO: Show in actual UI popup instead of just debug log } /// /// Check if position is within quest completion area /// public bool IsPositionInCompletionArea(Vector3 position) { if (activeQuest?.questData == null) return false; float distance = Vector3.Distance(transform.position, position); return distance <= activeQuest.questData.completionRadius; } /// /// Get distance to this quest marker from given position /// public float GetDistanceFrom(Vector3 position) { return Vector3.Distance(transform.position, position); } /// /// Show completion effect when quest is completed /// public void ShowCompletionEffect() { // Simple completion effect - change color and scale if (markerRenderer != null) { markerRenderer.material.color = Color.green; } // Animate scale up then destroy StartCoroutine(CompletionAnimation()); } private System.Collections.IEnumerator CompletionAnimation() { Vector3 originalScale = transform.localScale; float duration = 1f; float elapsed = 0f; while (elapsed < duration) { elapsed += Time.deltaTime; float progress = elapsed / duration; // Scale up then down float scaleMultiplier = 1f + Mathf.Sin(progress * Mathf.PI) * 0.5f; transform.localScale = originalScale * scaleMultiplier; // Fade out if (markerRenderer != null) { Color color = markerRenderer.material.color; color.a = 1f - progress; markerRenderer.material.color = color; } yield return null; } // Destroy the marker Destroy(gameObject); } #region Editor Gizmos private void OnDrawGizmos() { if (activeQuest?.questData == null) return; // Draw completion radius Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, activeQuest.questData.completionRadius); // Draw quest info var urgency = activeQuest.GetUrgency(); Gizmos.color = urgency switch { QuestUrgency.Low => Color.green, QuestUrgency.Medium => Color.yellow, QuestUrgency.High => new Color(1f, 0.5f, 0f), // orange QuestUrgency.Critical => Color.red, _ => Color.white }; Gizmos.DrawWireCube(transform.position, Vector3.one * 0.5f); } #endregion }