| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655 |
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- /// <summary>
- /// Simple standalone team placement script that randomly places the team on a settlement
- /// and creates a visible marker in front of the map.
- /// </summary>
- public class SimpleTeamPlacement : MonoBehaviour
- {
- [Header("Team Marker Settings")]
- public GameObject teamMarkerPrefab;
- public Material teamMarkerMaterial;
- [Range(0.5f, 3f)]
- public float markerSize = 1.5f;
- [Range(-5f, 5f)]
- public float markerHeight = 0.5f; // Y coordinate height above map tiles
- public Color markerColor = Color.green;
- [Header("Animation Settings")]
- public bool enableBlinking = true;
- [Range(0.1f, 2f)]
- public float blinkSpeed = 0.5f;
- // Private variables
- private GameObject teamMarkerInstance;
- private Vector2Int currentTeamPosition;
- private bool isTeamPositionSet = false;
- private bool isBlinking = false;
- private MapMaker2 mapMaker;
- public static SimpleTeamPlacement Instance { get; private set; }
- void Awake()
- {
- if (Instance == null)
- {
- Instance = this;
- }
- else
- {
- Debug.LogWarning("Multiple SimpleTeamPlacement instances found. Destroying this one.");
- Destroy(gameObject);
- return;
- }
- }
- void Start()
- {
- // Find MapMaker2
- mapMaker = FindFirstObjectByType<MapMaker2>();
- if (mapMaker == null)
- {
- return;
- }
- // Wait a bit for map generation, then place team
- StartCoroutine(WaitAndPlaceTeam());
- }
- void Update()
- {
- // Debug keys
- if (Input.GetKeyDown(KeyCode.R))
- {
- RandomlyPlaceTeam();
- }
- if (Input.GetKeyDown(KeyCode.M))
- {
- ShowMarkerInfo();
- }
- // Debug key to check saved positions
- if (Input.GetKeyDown(KeyCode.P))
- {
- DebugSavedPositions();
- }
- // Travel system integration - allow clicking on map to plan travel
- if (Input.GetKeyDown(KeyCode.T))
- {
- ShowTravelInfo();
- }
- }
- private IEnumerator WaitAndPlaceTeam()
- {
- // Wait for map generation
- yield return new WaitForSeconds(1.5f);
- // Check if this is a new game that should force random placement
- // First ensure GameStateManager exists, create it if needed
- if (GameStateManager.Instance == null)
- {
- GameObject gameStateObj = new GameObject("GameStateManager");
- gameStateObj.AddComponent<GameStateManager>();
- // Wait a frame for the GameStateManager to initialize
- yield return null;
- }
- bool isNewGame = GameStateManager.Instance?.IsNewGameForceRandom() ?? false;
- // ALWAYS show new game detection debug logs (even if showDebugLogs is false)
- if (isNewGame)
- {
- RandomlyPlaceTeam();
- // Clear the new game flag after placement
- GameStateManager.Instance?.ClearNewGameFlag();
- yield break;
- }
- // Try multiple times to load saved position (in case MapMaker2 isn't ready yet)
- int attempts = 0;
- const int maxAttempts = 5;
- while (attempts < maxAttempts)
- {
- attempts++;
- // Try to load saved position first
- if (TryLoadSavedPosition())
- {
- yield break; // Exit successfully
- }
- // If failed and MapMaker seed is still 0, wait a bit more
- if (mapMaker?.seed == 0 && attempts < maxAttempts)
- {
- yield return new WaitForSeconds(0.5f);
- }
- else
- {
- break; // Either loaded successfully or MapMaker is ready but no saved position
- }
- }
- // No saved position or invalid, place randomly
- RandomlyPlaceTeam();
- }
- private bool TryLoadSavedPosition()
- {
- // Get the current map seed to make position specific to this map
- int currentSeed = mapMaker?.seed ?? 0;
- string positionKey = $"TeamPosition_{currentSeed}";
- if (currentSeed == 0)
- {
- return false;
- }
- if (!PlayerPrefs.HasKey($"{positionKey}_X") || !PlayerPrefs.HasKey($"{positionKey}_Y"))
- {
- return false;
- }
- Vector2Int savedPosition = new Vector2Int(
- PlayerPrefs.GetInt($"{positionKey}_X"),
- PlayerPrefs.GetInt($"{positionKey}_Y")
- );
- // Verify position is still valid (any valid map position, not just settlements)
- if (IsValidMapPosition(savedPosition))
- {
- PlaceTeamAt(savedPosition);
- return true;
- }
- return false;
- }
- public void RandomlyPlaceTeam()
- {
- if (mapMaker?.GetMapData() == null)
- {
- return;
- }
- // For new games, ensure we're using the current random state for truly random placement
- bool isNewGame = GameStateManager.Instance?.IsNewGameForceRandom() ?? false;
- var mapData = mapMaker.GetMapData();
- var allSettlements = new List<Settlement>();
- // Combine towns and villages into one list for random selection
- allSettlements.AddRange(mapData.GetTowns());
- allSettlements.AddRange(mapData.GetVillages());
- if (allSettlements.Count == 0)
- {
- return;
- }
- // Randomly select a settlement
- int randomIndex = Random.Range(0, allSettlements.Count);
- Settlement selectedSettlement = allSettlements[randomIndex];
- PlaceTeamAt(selectedSettlement.position);
- }
- public void PlaceTeamAt(Vector2Int position)
- {
- currentTeamPosition = position;
- isTeamPositionSet = true;
- // Save position with map seed for persistence
- int currentSeed = mapMaker?.seed ?? 0;
- string positionKey = $"TeamPosition_{currentSeed}";
- bool isNewGame = GameStateManager.Instance?.IsNewGameForceRandom() ?? false;
- PlayerPrefs.SetInt($"{positionKey}_X", position.x);
- PlayerPrefs.SetInt($"{positionKey}_Y", position.y);
- PlayerPrefs.Save();
- // Create/update visual marker
- CreateTeamMarker();
- // Notify MapMaker2 of position change for event-driven exploration
- if (mapMaker != null)
- {
- mapMaker.OnTeamPositionChanged(position);
- }
- }
- /// <summary>
- /// Cleans up position data for old map seeds (optional maintenance)
- /// </summary>
- public void CleanupOldPositionData()
- {
- int currentSeed = mapMaker?.seed ?? 0;
- int cleanedCount = 0;
- // This is a simple cleanup - in a real game you might want more sophisticated management
- for (int i = 0; i < 10; i++) // Check last 10 potential seeds for cleanup
- {
- int testSeed = currentSeed - i;
- if (testSeed != currentSeed && testSeed > 0)
- {
- string positionKey = $"TeamPosition_{testSeed}";
- if (PlayerPrefs.HasKey($"{positionKey}_X"))
- {
- PlayerPrefs.DeleteKey($"{positionKey}_X");
- PlayerPrefs.DeleteKey($"{positionKey}_Y");
- cleanedCount++;
- }
- }
- }
- }
- /// <summary>
- /// Debug method to check what positions are saved in PlayerPrefs
- /// </summary>
- private void DebugSavedPositions()
- {
- int currentSeed = mapMaker?.seed ?? 0;
- // Check current seed position
- string currentKey = $"TeamPosition_{currentSeed}";
- bool hasCurrentPosition = PlayerPrefs.HasKey($"{currentKey}_X") && PlayerPrefs.HasKey($"{currentKey}_Y");
- if (hasCurrentPosition)
- {
- Vector2Int currentPos = new Vector2Int(
- PlayerPrefs.GetInt($"{currentKey}_X"),
- PlayerPrefs.GetInt($"{currentKey}_Y")
- );
- }
- else
- {
- }
- // Check for other potential seeds (common ones)
- int[] testSeeds = { 0, 12345, 1000, 5000, 9999 };
- foreach (int testSeed in testSeeds)
- {
- if (testSeed == currentSeed) continue; // Already checked
- string testKey = $"TeamPosition_{testSeed}";
- if (PlayerPrefs.HasKey($"{testKey}_X") && PlayerPrefs.HasKey($"{testKey}_Y"))
- {
- Vector2Int testPos = new Vector2Int(
- PlayerPrefs.GetInt($"{testKey}_X"),
- PlayerPrefs.GetInt($"{testKey}_Y")
- );
- }
- }
- }
- private void CreateTeamMarker()
- {
- // Stop any existing blinking first
- if (isBlinking)
- {
- StopAllCoroutines(); // This will stop the BlinkMarker coroutine
- isBlinking = false;
- }
- // Remove existing marker
- if (teamMarkerInstance != null)
- {
- DestroyImmediate(teamMarkerInstance);
- }
- // Create new marker
- if (teamMarkerPrefab != null)
- {
- teamMarkerInstance = Instantiate(teamMarkerPrefab);
- }
- else
- {
- // Create simple sphere marker
- teamMarkerInstance = GameObject.CreatePrimitive(PrimitiveType.Sphere);
- teamMarkerInstance.transform.localScale = Vector3.one * markerSize;
- teamMarkerInstance.tag = "Player";
- }
- // Position marker
- PositionMarker();
- // Apply material/color
- ApplyMarkerMaterial();
- // Set name
- teamMarkerInstance.name = "TeamMarker";
- // Start blinking if enabled
- if (enableBlinking)
- {
- StartBlinking();
- }
- }
- /// <summary>
- /// Get current team position
- /// </summary>
- public Vector2Int GetCurrentTeamPosition()
- {
- return currentTeamPosition;
- }
- /// <summary>
- /// Update team marker position when map coordinates change (called by exploration system)
- /// </summary>
- public void UpdateMarkerAfterMapChange(Vector2Int newVisiblePosition)
- {
- if (!isTeamPositionSet || teamMarkerInstance == null)
- {
- return;
- }
- // Store the world position before updating coordinates
- Vector3 currentWorldPos = teamMarkerInstance.transform.position;
- // Update the current team position to the new visible coordinates
- Vector2Int oldPosition = currentTeamPosition;
- currentTeamPosition = newVisiblePosition;
- // Reposition the marker to maintain world position consistency
- PositionMarker();
- }
- private void PositionMarker()
- {
- // Get tile size from MapVisualizer
- float tileSize = 1f;
- if (mapMaker?.mapVisualizer != null)
- {
- tileSize = mapMaker.mapVisualizer.tileSize;
- }
- // Calculate world position:
- // In exploration mode, we need to convert exploration coordinates to full map coordinates for world positioning
- Vector2Int worldCoordinates = currentTeamPosition;
- // Check if we're using exploration system
- if (mapMaker != null && mapMaker.useExplorationSystem)
- {
- var explorationManager = mapMaker.GetExplorationManager();
- if (explorationManager != null)
- {
- // Use exploration manager to convert coordinates properly
- Vector3 correctWorldPos = explorationManager.ConvertExplorationToWorldCoordinates(currentTeamPosition);
- teamMarkerInstance.transform.position = new Vector3(
- correctWorldPos.x,
- markerHeight, // Y coordinate height above map tiles
- correctWorldPos.z // Use Z coordinate for map Y position
- );
- return;
- }
- }
- // Fallback for non-exploration mode: use direct coordinate mapping
- Vector3 worldPosition = new Vector3(
- worldCoordinates.x * tileSize,
- markerHeight, // Y coordinate height above map tiles
- worldCoordinates.y * tileSize // Map Y becomes world Z for top-down view
- );
- teamMarkerInstance.transform.position = worldPosition;
- }
- private void ApplyMarkerMaterial()
- {
- Renderer renderer = teamMarkerInstance.GetComponent<Renderer>();
- if (renderer == null) return;
- if (teamMarkerMaterial != null)
- {
- renderer.material = teamMarkerMaterial;
- }
- else
- {
- // Create simple colored material using URP shaders first
- Shader shader = null;
- // Try URP shaders first
- shader = Shader.Find("Universal Render Pipeline/Lit");
- if (shader == null)
- shader = Shader.Find("Universal Render Pipeline/Simple Lit");
- if (shader == null)
- shader = Shader.Find("Universal Render Pipeline/Unlit");
- // Fallback to built-in shaders
- if (shader == null)
- shader = Shader.Find("Standard");
- if (shader == null)
- shader = Shader.Find("Legacy Shaders/Diffuse");
- if (shader == null)
- shader = Shader.Find("Unlit/Color");
- // Last resort fallback
- if (shader == null)
- {
- return;
- }
- Material material = new Material(shader);
- // Set base color (works for both URP and built-in)
- if (material.HasProperty("_BaseColor"))
- {
- material.SetColor("_BaseColor", markerColor); // URP property
- }
- else if (material.HasProperty("_Color"))
- {
- material.SetColor("_Color", markerColor); // Built-in property
- }
- material.color = markerColor; // Fallback
- // Add emission for better visibility
- if (material.HasProperty("_EmissionColor"))
- {
- material.EnableKeyword("_EMISSION");
- material.SetColor("_EmissionColor", markerColor * 0.3f);
- }
- renderer.material = material;
- }
- }
- private void StartBlinking()
- {
- if (!isBlinking)
- {
- StartCoroutine(BlinkMarker());
- }
- else
- {
- // Force restart blinking as a fallback
- StopAllCoroutines();
- isBlinking = false;
- StartCoroutine(BlinkMarker());
- }
- }
- private IEnumerator BlinkMarker()
- {
- isBlinking = true;
- Renderer markerRenderer = teamMarkerInstance?.GetComponent<Renderer>();
- if (markerRenderer == null)
- {
- isBlinking = false;
- yield break;
- }
- // Capture the enableBlinking state at start to avoid timing issues
- bool shouldBlink = enableBlinking;
- int blinkCount = 0;
- while (teamMarkerInstance != null && markerRenderer != null && shouldBlink)
- {
- // Hide marker
- markerRenderer.enabled = false;
- yield return new WaitForSeconds(blinkSpeed);
- // Show marker
- if (markerRenderer != null && teamMarkerInstance != null)
- {
- markerRenderer.enabled = true;
- yield return new WaitForSeconds(blinkSpeed);
- blinkCount++;
- }
- else
- {
- break;
- }
- // Re-check enableBlinking periodically (every 10 blinks) in case user changes it
- if (blinkCount % 10 == 0)
- {
- shouldBlink = enableBlinking;
- }
- }
- isBlinking = false;
- }
- private bool IsValidSettlementPosition(Vector2Int position)
- {
- if (mapMaker?.GetMapData() == null) return false;
- var mapData = mapMaker.GetMapData();
- if (!mapData.IsValidPosition(position.x, position.y)) return false;
- // Check if position has a settlement
- foreach (var town in mapData.GetTowns())
- {
- if (town.position == position) return true;
- }
- foreach (var village in mapData.GetVillages())
- {
- if (village.position == position) return true;
- }
- return false;
- }
- /// <summary>
- /// Checks if a position is valid for team placement (any valid map position)
- /// Used for persistent positioning - team can be anywhere on the map
- /// </summary>
- private bool IsValidMapPosition(Vector2Int position)
- {
- if (mapMaker?.GetMapData() == null)
- {
- return false;
- }
- var mapData = mapMaker.GetMapData();
- return mapData.IsValidPosition(position.x, position.y);
- }
- private void ShowMarkerInfo()
- {
- if (teamMarkerInstance == null)
- {
- return;
- }
- }
- private void ShowTravelInfo()
- {
- var travelSystem = TeamTravelSystem.Instance;
- if (travelSystem != null)
- {
- }
- else
- {
- }
- }
- // Public methods for external control
- public Vector2Int GetTeamPosition() => currentTeamPosition;
- public bool IsTeamPlaced() => isTeamPositionSet;
- public GameObject GetTeamMarker() => teamMarkerInstance;
- [ContextMenu("Randomly Place Team")]
- public void ContextRandomlyPlaceTeam()
- {
- RandomlyPlaceTeam();
- }
- [ContextMenu("Show Marker Info")]
- public void ContextShowMarkerInfo()
- {
- ShowMarkerInfo();
- }
- [ContextMenu("Force New Game Random Placement")]
- public void ContextForceNewGamePlacement()
- {
- // Temporarily set new game flag for testing
- if (GameStateManager.Instance != null)
- {
- GameStateManager.Instance.isNewGame = true;
- }
- RandomlyPlaceTeam();
- // Clear the flag after testing
- GameStateManager.Instance?.ClearNewGameFlag();
- }
- }
|