using UnityEngine;
using System.Collections;
using System.Collections.Generic;
///
/// Simple standalone team placement script that randomly places the team on a settlement
/// and creates a visible marker in front of the map.
///
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; }
///
/// Gets the current team marker GameObject instance
///
public GameObject TeamMarkerInstance => teamMarkerInstance;
///
/// Gets the world position of the team marker
///
public Vector3 TeamMarkerWorldPosition
{
get
{
if (teamMarkerInstance != null)
return teamMarkerInstance.transform.position;
return Vector3.zero;
}
}
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();
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();
// 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();
// 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);
}
}
///
/// Cleans up position data for old map seeds (optional maintenance)
///
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++;
}
}
}
}
///
/// Debug method to check what positions are saved in PlayerPrefs
///
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();
}
// Notify camera to center on the newly created team marker
var cameraController = FindFirstObjectByType();
if (cameraController != null)
{
cameraController.OnTeamMarkerCreated();
}
}
///
/// Get current team position
///
public Vector2Int GetCurrentTeamPosition()
{
return currentTeamPosition;
}
///
/// Update team marker position when map coordinates change (called by exploration system)
///
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();
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();
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;
}
///
/// Checks if a position is valid for team placement (any valid map position)
/// Used for persistent positioning - team can be anywhere on the map
///
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();
}
}