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;
Debug.Log($"🎯 Clicked quest marker: {activeQuest.questData.questTitle}");
// 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";
Debug.Log($"📋 Quest Info:\n{info}");
// 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
}