BattleSetup.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.AI;
  4. public class BattleSetup : MonoBehaviour
  5. {
  6. List<GameObject> unplacedEnemyCharacters = new List<GameObject>();
  7. List<GameObject> placedPlayerCharacters = new List<GameObject>();
  8. List<GameObject> placedEnemyCharacters = new List<GameObject>();
  9. private List<GameObject> playerCharacters = new List<GameObject>();
  10. private List<GameObject> enemyCharacters = new List<GameObject>();
  11. private List<CharacterSelection> playerSelections = new List<CharacterSelection>();
  12. private List<CharacterSelection> enemySelections = new List<CharacterSelection>();
  13. [Tooltip("Select the layer(s) that represent the ground for raycasting.")]
  14. public LayerMask groundLayerMask;
  15. public GameObject playerPrefab; // Assign in the inspector or through GameManager
  16. public GameObject enemyPrefab; // Assign in the inspector or through GameManager
  17. public GameObject SwordPrefab; // Assign in the inspector or through GameManager
  18. public GameObject BowPrefab; // Assign in the inspector or through GameManager
  19. GameObject playerSpawnArea;
  20. GameObject enemySpawnArea;
  21. Bounds playerSpawnBounds;
  22. private Camera mainCamera;
  23. private GameObject currentPlacingCharacterInstance;
  24. private int nextPlayerCharacterPrefabIndex = 0;
  25. private bool isPlacingPlayerCharacters = false;
  26. void Awake()
  27. {
  28. mainCamera = Camera.main;
  29. if (mainCamera == null)
  30. {
  31. Debug.LogError("Main camera not found. Please ensure there is a camera tagged as 'MainCamera' in the scene.");
  32. enabled = false;
  33. return;
  34. }
  35. playerCharacters.Clear();
  36. enemyCharacters.Clear();
  37. // Store the selections for use during placement
  38. playerSelections = new List<CharacterSelection>(BattleSetupData.playerSelections);
  39. enemySelections = new List<CharacterSelection>(BattleSetupData.enemySelections);
  40. // Initialize the lists with characters from the game manager or other sources
  41. playerSpawnArea = GameObject.Find("PlayerSpawnArea");
  42. enemySpawnArea = GameObject.Find("EnemySpawnArea");
  43. if (playerSpawnArea == null)
  44. {
  45. Debug.LogError("PlayerSpawnArea GameObject not found in scene. Please ensure there is a GameObject named 'PlayerSpawnArea' in the scene.");
  46. enabled = false;
  47. return;
  48. }
  49. Collider playerSpawnAreaCollider = playerSpawnArea.GetComponent<Collider>();
  50. if (playerSpawnAreaCollider == null)
  51. {
  52. Debug.LogError("PlayerSpawnArea does not have a collider component.");
  53. enabled = false;
  54. return;
  55. }
  56. playerSpawnBounds = playerSpawnAreaCollider.bounds;
  57. if (enemySpawnArea == null)
  58. {
  59. // Enemy placement might still work if unplacedEnemyCharacters is empty
  60. Debug.LogWarning("EnemySpawnArea GameObject not found in the scene. Enemy placement might be affected.");
  61. }
  62. // Call the setup methods to place characters
  63. PlaceEnemyCharacters();
  64. InitiatePlayerCharacterPlacement();
  65. }
  66. // Helper method to get WeaponItem from CombatDataTransfer if available
  67. WeaponItem GetEnhancedWeaponItem(string characterName, bool isPlayer)
  68. {
  69. Debug.Log($"🔍 GetEnhancedWeaponItem called for '{characterName}', isPlayer: {isPlayer}");
  70. if (!CombatDataTransfer.HasValidSession())
  71. {
  72. Debug.Log($"🔍 No valid CombatDataTransfer session");
  73. return null;
  74. }
  75. var session = CombatDataTransfer.GetCurrentSession();
  76. if (session == null)
  77. {
  78. Debug.Log($"🔍 CombatDataTransfer session is null");
  79. return null;
  80. }
  81. Debug.Log($"🔍 Session has {session.playerTeam.Count} players and {session.enemies.Count} enemies");
  82. if (isPlayer)
  83. {
  84. // Debug: List all available player characters
  85. Debug.Log($"🔍 Available players in session:");
  86. foreach (var player in session.playerTeam)
  87. {
  88. Debug.Log($" - Player: '{player.characterName}', Weapon: {(player.equippedWeaponItem != null ? player.equippedWeaponItem.name : "NULL")}");
  89. }
  90. // Find player character in enhanced data (match by base name, ignoring suffixes)
  91. foreach (var player in session.playerTeam)
  92. {
  93. if (player.characterName == characterName && player.equippedWeaponItem != null)
  94. {
  95. Debug.Log($"🎯 Found enhanced WeaponItem for player {characterName}: {player.equippedWeaponItem.name}");
  96. return player.equippedWeaponItem;
  97. }
  98. // Also try matching without the numbered suffix (e.g., "Player 1" vs "Player")
  99. if (characterName.StartsWith(player.characterName) && player.equippedWeaponItem != null)
  100. {
  101. Debug.Log($"🎯 Found enhanced WeaponItem for player {characterName} (matched base name {player.characterName}): {player.equippedWeaponItem.name}");
  102. return player.equippedWeaponItem;
  103. }
  104. }
  105. Debug.Log($"🔍 No matching player found for '{characterName}'");
  106. }
  107. else
  108. {
  109. // Find enemy character in enhanced data (match by base name, ignoring suffixes)
  110. foreach (var enemy in session.enemies)
  111. {
  112. if (enemy.enemyName == characterName && enemy.preferredWeaponItem != null)
  113. {
  114. Debug.Log($"🎯 Found enhanced WeaponItem for enemy {characterName}: {enemy.preferredWeaponItem.name}");
  115. return enemy.preferredWeaponItem;
  116. }
  117. // Also try matching the base name (e.g., "Skeleton Warrior_1" vs "Skeleton Warrior")
  118. if (characterName.StartsWith(enemy.enemyType) && enemy.preferredWeaponItem != null)
  119. {
  120. Debug.Log($"🎯 Found enhanced WeaponItem for enemy {characterName} (matched base type {enemy.enemyType}): {enemy.preferredWeaponItem.name}");
  121. return enemy.preferredWeaponItem;
  122. }
  123. }
  124. }
  125. return null;
  126. }
  127. /// <summary>
  128. /// Apply team character stats from combat data to a Character instance
  129. /// </summary>
  130. private void ApplyTeamDataToCharacter(Character character, string characterName)
  131. {
  132. var sessionData = CombatDataTransfer.GetCurrentSession();
  133. if (sessionData == null)
  134. {
  135. Debug.LogWarning($"No combat session data found for character: {characterName}");
  136. return;
  137. }
  138. // Find the team character data (match by exact name or base name)
  139. var teamData = sessionData.playerTeam?.Find(p => p.characterName == characterName);
  140. if (teamData == null)
  141. {
  142. // Try to match base name without suffix
  143. teamData = sessionData.playerTeam?.Find(p => characterName.StartsWith(p.characterName));
  144. }
  145. if (teamData != null)
  146. {
  147. character.ApplyStatsFromCombatData(teamData);
  148. Debug.Log($"📊 Applied team stats to {characterName}: STR:{teamData.strength} DEX:{teamData.dexterity} CON:{teamData.constitution} WIS:{teamData.wisdom} PER:{teamData.perception}");
  149. }
  150. else
  151. {
  152. Debug.LogWarning($"No team data found for character: {characterName}");
  153. }
  154. }
  155. /// <summary>
  156. /// Apply enemy character stats from combat data to a Character instance
  157. /// </summary>
  158. private void ApplyEnemyDataToCharacter(Character character, string characterName)
  159. {
  160. var sessionData = CombatDataTransfer.GetCurrentSession();
  161. if (sessionData == null)
  162. {
  163. Debug.LogWarning($"No combat session data found for enemy: {characterName}");
  164. return;
  165. }
  166. // Find the enemy character data (match by exact name or base type)
  167. var enemyData = sessionData.enemies?.Find(e => e.enemyName == characterName);
  168. if (enemyData == null)
  169. {
  170. // Try to match base type without suffix
  171. enemyData = sessionData.enemies?.Find(e => characterName.StartsWith(e.enemyType));
  172. }
  173. if (enemyData != null)
  174. {
  175. character.ApplyStatsFromCombatData(enemyData);
  176. Debug.Log($"📊 Applied enemy stats to {characterName}");
  177. }
  178. else
  179. {
  180. Debug.LogWarning($"No enemy data found for character: {characterName}");
  181. }
  182. }
  183. // Enhanced weapon equipping with WeaponItem support
  184. void EquipWeapon(Character character, WeaponItem weaponItem)
  185. {
  186. Debug.Log($"🔧 EquipWeapon called for {character.CharacterName} with WeaponItem: {(weaponItem != null ? weaponItem.name : "null")}");
  187. Weapon weapon = null;
  188. if (weaponItem != null)
  189. {
  190. Debug.Log($"🔧 Using WeaponItem.CreateWeaponInstance() for {weaponItem.name}");
  191. // Use the WeaponItem's CreateWeaponInstance method to preserve all attributes
  192. weapon = weaponItem.CreateWeaponInstance(character.transform);
  193. if (weapon != null)
  194. {
  195. weapon.SetWielder(character);
  196. Debug.Log($"✅ Successfully created weapon from WeaponItem: {weapon.weaponName}");
  197. }
  198. else
  199. {
  200. Debug.LogWarning($"⚠️ WeaponItem.CreateWeaponInstance() returned null for {weaponItem.name}. Falling back to string-based creation.");
  201. // Fallback to string-based weapon creation
  202. EquipWeapon(character, weaponItem.weaponType.ToString());
  203. return;
  204. }
  205. }
  206. else
  207. {
  208. Debug.LogWarning($"No WeaponItem provided for {character.CharacterName}. Equipping with fists as fallback.");
  209. EquipWeapon(character, "Fists");
  210. return;
  211. }
  212. if (weapon != null)
  213. {
  214. // Attach weapon to the character
  215. Transform attachPoint = character.transform.Find("WeaponAttachPoint");
  216. if (attachPoint != null)
  217. {
  218. weapon.transform.SetParent(attachPoint, false);
  219. weapon.transform.localPosition = Vector3.zero;
  220. weapon.transform.localRotation = Quaternion.identity;
  221. }
  222. else
  223. {
  224. weapon.transform.SetParent(character.transform, false);
  225. weapon.transform.localPosition = new Vector3(0.5f, 0, 0);
  226. }
  227. character.Weapon = weapon;
  228. weapon.SetWielder(character);
  229. Debug.Log($"✅ Successfully equipped {weapon.weaponName} to {character.CharacterName}");
  230. }
  231. else
  232. {
  233. Debug.LogError($"❌ Failed to create weapon for {character.CharacterName}");
  234. }
  235. }
  236. // Fallback weapon equipping using string types (for backward compatibility)
  237. void EquipWeapon(Character character, string weaponType)
  238. {
  239. Debug.Log($"🔧 EquipWeapon called for {character.CharacterName} with weaponType: '{weaponType}'");
  240. Weapon weapon = null;
  241. // Handle null or empty weapon types
  242. if (string.IsNullOrEmpty(weaponType))
  243. {
  244. Debug.LogWarning($"No weapon type specified for {character.CharacterName}. Equipping with fists as fallback.");
  245. weaponType = "Fists";
  246. }
  247. Debug.Log($"🔧 Processing weapon type: '{weaponType}' for {character.CharacterName}");
  248. if (weaponType == "Sword")
  249. {
  250. Debug.Log($"⚔️ Creating Sword for {character.CharacterName}");
  251. var weaponObj = Instantiate(SwordPrefab, character.transform);
  252. weapon = weaponObj.GetComponent<Weapon>();
  253. }
  254. else if (weaponType == "Bow")
  255. {
  256. Debug.Log($"🏹 Creating Bow for {character.CharacterName}");
  257. var weaponObj = Instantiate(BowPrefab, character.transform);
  258. weapon = weaponObj.GetComponent<Weapon>();
  259. }
  260. else if (weaponType == "Fists")
  261. {
  262. Debug.Log($"👊 Creating Fists for {character.CharacterName}");
  263. // Create a fists weapon directly using SimpleSword as base
  264. GameObject fistsObj = new GameObject("Fists");
  265. fistsObj.transform.SetParent(character.transform, false);
  266. SimpleSword fistsWeapon = fistsObj.AddComponent<SimpleSword>();
  267. // Override the sword's properties to make it act like fists
  268. fistsWeapon.weaponName = "Fists";
  269. fistsWeapon.description = "Bare fists - a basic unarmed attack.";
  270. fistsWeapon.attackSpeed = 1.0f;
  271. weapon = fistsWeapon;
  272. }
  273. else
  274. {
  275. Debug.LogWarning($"❓ Unknown weapon type: '{weaponType}' for {character.CharacterName}. Equipping with fists as fallback.");
  276. // Create a fists weapon as fallback using SimpleSword as base
  277. GameObject fistsObj = new GameObject("Fists");
  278. fistsObj.transform.SetParent(character.transform, false);
  279. SimpleSword fistsWeapon = fistsObj.AddComponent<SimpleSword>();
  280. // Override the sword's properties to make it act like fists
  281. fistsWeapon.weaponName = "Fists";
  282. fistsWeapon.description = "Bare fists - a basic unarmed attack.";
  283. fistsWeapon.attackSpeed = 1.0f;
  284. weapon = fistsWeapon;
  285. }
  286. if (weapon != null)
  287. {
  288. Transform attachPoint = character.transform.Find("WeaponAttachPoint");
  289. if (attachPoint != null)
  290. {
  291. weapon.transform.SetParent(attachPoint, false);
  292. weapon.transform.localPosition = Vector3.zero;
  293. weapon.transform.localRotation = Quaternion.identity;
  294. }
  295. else
  296. {
  297. weapon.transform.SetParent(character.transform, false);
  298. weapon.transform.localPosition = new Vector3(0.5f, 0, 0);
  299. }
  300. character.Weapon = weapon;
  301. weapon.SetWielder(character);
  302. Debug.Log($"✅ Successfully equipped {weapon.weaponName} to {character.CharacterName}");
  303. }
  304. else
  305. {
  306. Debug.LogError($"❌ Failed to create weapon for {character.CharacterName}");
  307. }
  308. }
  309. void Update()
  310. {
  311. if (!isPlacingPlayerCharacters || currentPlacingCharacterInstance == null)
  312. {
  313. return;
  314. }
  315. HandleCharacterPlacement();
  316. }
  317. private void InitiatePlayerCharacterPlacement()
  318. {
  319. if (playerSelections.Count == 0)
  320. {
  321. return;
  322. }
  323. isPlacingPlayerCharacters = true;
  324. nextPlayerCharacterPrefabIndex = 0;
  325. SpawnNextPlayerCharacterForPlacement();
  326. }
  327. private void SpawnNextPlayerCharacterForPlacement()
  328. {
  329. if (currentPlacingCharacterInstance != null)
  330. {
  331. // This case should ideally not happen if logic flows correctly,
  332. // but as a safeguard if a previous instance wasn't cleaned up.
  333. Destroy(currentPlacingCharacterInstance);
  334. currentPlacingCharacterInstance = null;
  335. }
  336. if (nextPlayerCharacterPrefabIndex < playerSelections.Count)
  337. {
  338. var selection = playerSelections[nextPlayerCharacterPrefabIndex];
  339. currentPlacingCharacterInstance = Instantiate(playerPrefab);
  340. currentPlacingCharacterInstance.name = selection.characterName;
  341. var character = currentPlacingCharacterInstance.GetComponent<Character>();
  342. if (character != null)
  343. {
  344. Debug.Log($"🔍 SpawnNextPlayerCharacterForPlacement: Character '{selection.characterName}' with weapon '{selection.weaponType}'");
  345. // Apply team data stats to the character
  346. ApplyTeamDataToCharacter(character, selection.characterName);
  347. // Try to get enhanced weapon data first
  348. WeaponItem enhancedWeapon = GetEnhancedWeaponItem(selection.characterName, true);
  349. Debug.Log($"🔍 Enhanced weapon lookup for '{selection.characterName}': {(enhancedWeapon != null ? enhancedWeapon.name : "NULL")}");
  350. if (enhancedWeapon != null)
  351. {
  352. Debug.Log($"🎯 Using enhanced weapon: {enhancedWeapon.name}");
  353. EquipWeapon(character, enhancedWeapon);
  354. }
  355. else
  356. {
  357. Debug.Log($"🔍 No enhanced weapon found, falling back to selection.weaponType: '{selection.weaponType}'");
  358. EquipWeapon(character, selection.weaponType);
  359. }
  360. character.CharacterName = selection.characterName + " " + (nextPlayerCharacterPrefabIndex + 1);
  361. }
  362. currentPlacingCharacterInstance.GetComponent<NavMeshAgent>().enabled = false;
  363. // Optionally disable AI or other components that might interfere with placement
  364. // e.g., currentPlacingCharacterInstance.GetComponent<AIController>()?.enabled = false;
  365. }
  366. else
  367. {
  368. FinalizePlayerPlacement();
  369. }
  370. }
  371. private void HandleCharacterPlacement()
  372. {
  373. Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
  374. Debug.DrawRay(ray.origin, ray.direction * 200f, Color.yellow); // Visualize the ray
  375. if (Physics.Raycast(ray, out RaycastHit hit, 200f, groundLayerMask))
  376. {
  377. Vector3 targetPosition = hit.point;
  378. // Clamp position to playerSpawnArea bound (X and Z axis)
  379. targetPosition.x = Mathf.Clamp(targetPosition.x, playerSpawnBounds.min.x, playerSpawnBounds.max.x);
  380. targetPosition.z = Mathf.Clamp(targetPosition.z, playerSpawnBounds.min.z, playerSpawnBounds.max.z);
  381. // Y is determined by the raycast hit on the ground
  382. // --- Direct Y Position Calculation for Mouse-Following Character ---
  383. // This approach was found to be more stable than repeatedly calling AdjustCharacterOnGround.
  384. // It assumes a standard Unity CapsuleCollider where the pivot is at the center.
  385. Vector3 finalCharacterPosition = targetPosition; // targetPosition.y is from the ground hit (hit.point.y)
  386. CapsuleCollider capCollider = currentPlacingCharacterInstance.GetComponent<CapsuleCollider>();
  387. if (capCollider != null)
  388. {
  389. // For a capsule, its pivot is typically at its center.
  390. // To place its bottom on targetPosition.y (ground level),
  391. // its center (pivot) needs to be at targetPosition.y + (height / 2).
  392. // We also account for the character's local scale.
  393. finalCharacterPosition.y = targetPosition.y + (capCollider.height * currentPlacingCharacterInstance.transform.localScale.y / 2f);
  394. }
  395. else
  396. {
  397. // Fallback if not a capsule or if a different pivot is used.
  398. // This might need adjustment based on your character's actual pivot and collider.
  399. Debug.LogWarning($"'{currentPlacingCharacterInstance.name}' does not have a CapsuleCollider. Using default Y offset for placement. Adjust if incorrect.");
  400. finalCharacterPosition.y = targetPosition.y + 0.5f; // Example offset, adjust as needed
  401. }
  402. currentPlacingCharacterInstance.transform.position = finalCharacterPosition;
  403. // AdjustCharacterOnGround(currentPlacingCharacterInstance); // No longer called every frame for mouse-follow
  404. }
  405. else
  406. {
  407. }
  408. // Else mouse is not over valid ground, character stays at last valid position or initial spawn
  409. if (Input.GetMouseButtonDown(0))
  410. { // Left-click to place character
  411. // Check if the current position is valid (within bounds and not overlapping)
  412. // The position is already clamped and on ground due to the logic above.
  413. // We primarily need to check for overlaps.
  414. if (!IsOverlappingOtherCharacters(currentPlacingCharacterInstance))
  415. {
  416. PlaceCurrentCharacter();
  417. }
  418. else
  419. {
  420. Debug.LogWarning("Cannot place character: Overlapping with another character.");
  421. // Optionally, you could provide feedback to the player about the overlap (e.g. change color?).
  422. }
  423. }
  424. if (Input.GetMouseButtonDown(1))
  425. { // Right-click to cancel placement
  426. if (placedPlayerCharacters.Count > 0)
  427. {
  428. FinalizePlayerPlacement();
  429. }
  430. else
  431. {
  432. }
  433. }
  434. }
  435. private void PlaceCurrentCharacter()
  436. {
  437. placedPlayerCharacters.Add(currentPlacingCharacterInstance);
  438. currentPlacingCharacterInstance = null;
  439. nextPlayerCharacterPrefabIndex++;
  440. SpawnNextPlayerCharacterForPlacement(); // Spawn next character for placement
  441. }
  442. private void AdjustCharacterOnGround(GameObject character)
  443. {
  444. if (character == null)
  445. {
  446. return;
  447. }
  448. Collider charCollider = character.GetComponent<Collider>();
  449. if (charCollider != null)
  450. {
  451. // This ensured the lowest point of the collider is at character.transform.position.y
  452. // (which should be the ground hit point)
  453. // currentY is the Y-coordinate of the character's pivot.
  454. // We want the character's collider bottom (feet) to be at this Y-level.
  455. float currentY = character.transform.position.y;
  456. float colliderMinYWorld = charCollider.bounds.min.y;
  457. float verticalOffset = currentY - colliderMinYWorld;
  458. const float tolerance = 0.001f; // Small tolerance to avoid floating point issues
  459. if (Mathf.Abs(verticalOffset) > tolerance)
  460. {
  461. character.transform.position += Vector3.up * verticalOffset;
  462. }
  463. }
  464. else
  465. {
  466. Debug.LogWarning($"Character: {character.name} has no collider. Cannot accurately adjust to ground.");
  467. }
  468. }
  469. private bool IsOverlappingOtherCharacters(GameObject character)
  470. {
  471. Collider newCharCollider = character.GetComponent<Collider>();
  472. if (newCharCollider == null)
  473. {
  474. Debug.LogWarning($"Character: {character.name} has no collider. Cannot check for overlaps.");
  475. return false; // Or true to precent placement if no collider
  476. }
  477. Bounds newCharBounds = newCharCollider.bounds;
  478. foreach (GameObject placedCharacter in placedPlayerCharacters)
  479. {
  480. Collider otherCollider = placedCharacter.GetComponent<Collider>();
  481. if (otherCollider != null && newCharBounds.Intersects(otherCollider.bounds))
  482. {
  483. return true;
  484. }
  485. }
  486. foreach (GameObject placedEnemy in placedEnemyCharacters)
  487. {
  488. Collider otherCollider = placedEnemy.GetComponent<Collider>();
  489. if (otherCollider != null && newCharBounds.Intersects(otherCollider.bounds))
  490. {
  491. return true;
  492. }
  493. }
  494. return false;
  495. }
  496. private void FinalizePlayerPlacement()
  497. {
  498. isPlacingPlayerCharacters = false;
  499. if (currentPlacingCharacterInstance != null)
  500. {
  501. Destroy(currentPlacingCharacterInstance); // Destroy the preview instance if it wasn't placed
  502. currentPlacingCharacterInstance = null;
  503. }
  504. EndPlacementPhase();
  505. // Here you might want to trigger the next phase of your game, e.g., start the battle.
  506. GameManager.Instance.StartBattle(placedPlayerCharacters, placedEnemyCharacters);
  507. Destroy(playerSpawnArea);
  508. Destroy(enemySpawnArea);
  509. playerSpawnArea = null;
  510. enemySpawnArea = null;
  511. }
  512. private void EndPlacementPhase()
  513. {
  514. // This method can be used to clean up or finalize the placement phase.
  515. // For example, you might want to enable AI, re-enable NavMeshAgents, etc.
  516. foreach (GameObject character in placedPlayerCharacters)
  517. {
  518. NavMeshAgent agent = character.GetComponent<NavMeshAgent>();
  519. if (agent != null)
  520. {
  521. agent.enabled = true; // Re-enable NavMeshAgent
  522. }
  523. // Add carry capacity system to player characters
  524. AddCarryCapacityComponent(character);
  525. // Enable AI or other components as needed
  526. // e.g., character.GetComponent<AIController>()?.enabled = true;
  527. }
  528. foreach (GameObject character in enemyCharacters)
  529. {
  530. NavMeshAgent agent = character.GetComponent<NavMeshAgent>();
  531. if (agent != null)
  532. {
  533. agent.enabled = true; // Re-enable NavMeshAgent
  534. }
  535. // Add carry capacity system to enemy characters too (for consistency)
  536. AddCarryCapacityComponent(character);
  537. // Enable AI or other components as needed
  538. // e.g., character.GetComponent<AIController>()?.enabled = true;
  539. }
  540. }
  541. /// <summary>
  542. /// Add CharacterCarryCapacity component to a character GameObject
  543. /// </summary>
  544. private void AddCarryCapacityComponent(GameObject characterObj)
  545. {
  546. if (characterObj == null) return;
  547. // Only add if it doesn't already exist
  548. var existingCapacity = characterObj.GetComponent<CharacterCarryCapacity>();
  549. if (existingCapacity != null) return;
  550. var character = characterObj.GetComponent<Character>();
  551. if (character == null) return;
  552. // Add the carry capacity component
  553. var carryCapacity = characterObj.AddComponent<CharacterCarryCapacity>();
  554. // Configure based on character type/name
  555. ConfigureCarryCapacity(carryCapacity, character);
  556. Debug.Log($"📦 Added carry capacity system to {character.CharacterName}");
  557. }
  558. /// <summary>
  559. /// Configure carry capacity settings based on character
  560. /// </summary>
  561. private void ConfigureCarryCapacity(CharacterCarryCapacity carryCapacity, Character character)
  562. {
  563. if (carryCapacity == null || character == null) return;
  564. // Adjust settings based on character type or name
  565. string characterName = character.CharacterName.ToLower();
  566. if (characterName.Contains("warrior") || characterName.Contains("fighter"))
  567. {
  568. // Warriors can carry more
  569. carryCapacity.carrySystem.baseCarryCapacity = 60;
  570. carryCapacity.carrySystem.strengthMultiplier = 6f;
  571. }
  572. else if (characterName.Contains("rogue") || characterName.Contains("thief"))
  573. {
  574. // Rogues are more agile but carry less
  575. carryCapacity.carrySystem.baseCarryCapacity = 40;
  576. carryCapacity.carrySystem.strengthMultiplier = 4f;
  577. carryCapacity.carrySystem.lightLoadThreshold = 0.4f; // Stay light more often
  578. }
  579. else if (characterName.Contains("mage") || characterName.Contains("wizard"))
  580. {
  581. // Mages have lower physical capacity
  582. carryCapacity.carrySystem.baseCarryCapacity = 35;
  583. carryCapacity.carrySystem.strengthMultiplier = 3f;
  584. }
  585. else
  586. {
  587. // Default settings are already good for most characters
  588. carryCapacity.carrySystem.baseCarryCapacity = 50;
  589. carryCapacity.carrySystem.strengthMultiplier = 5f;
  590. }
  591. // Enable debug info for player characters
  592. if (character.CompareTag("Player"))
  593. {
  594. carryCapacity.showDebugInfo = true;
  595. }
  596. }
  597. private void PlaceEnemyCharacters()
  598. {
  599. Collider spawnAreaCollider = enemySpawnArea.GetComponent<Collider>();
  600. if (spawnAreaCollider == null)
  601. {
  602. Debug.LogError("Enemy spawn area does not have a collider component.");
  603. return;
  604. }
  605. Bounds spawnBounds = spawnAreaCollider.bounds;
  606. for (int i = enemySelections.Count - 1; i >= 0; i--)
  607. {
  608. var selection = enemySelections[i];
  609. float randomX = UnityEngine.Random.Range(spawnBounds.min.x, spawnBounds.max.x);
  610. float randomZ = UnityEngine.Random.Range(spawnBounds.min.z, spawnBounds.max.z);
  611. Vector3 rayOrigin = new Vector3(randomX, enemySpawnArea.transform.position.y + 10f, randomZ);
  612. Vector3 spawnPosition = new Vector3(randomX, enemySpawnArea.transform.position.y, randomZ);
  613. // Raycast to find the ground
  614. if (Physics.Raycast(rayOrigin, Vector3.down, out RaycastHit hit, 200f, groundLayerMask))
  615. {
  616. spawnPosition = hit.point;
  617. }
  618. else
  619. {
  620. Debug.LogWarning($"Raycast did not hit ground below ({randomX}, {randomZ}). Placing enemy at spawn area Y level.");
  621. }
  622. GameObject placedEnemy = Instantiate(enemyPrefab, spawnPosition, Quaternion.identity);
  623. Character character = placedEnemy.GetComponent<Character>();
  624. if (character != null)
  625. {
  626. // Apply enemy data stats to the character
  627. ApplyEnemyDataToCharacter(character, selection.characterName);
  628. // Try to get enhanced weapon data first
  629. WeaponItem enhancedWeapon = GetEnhancedWeaponItem(selection.characterName, false);
  630. if (enhancedWeapon != null)
  631. {
  632. EquipWeapon(character, enhancedWeapon);
  633. }
  634. else
  635. {
  636. EquipWeapon(character, selection.weaponType);
  637. }
  638. character.CharacterName = selection.characterName + "_" + (i + 1);
  639. }
  640. AdjustCharacterOnGround(placedEnemy); // Adjust the enemy to the ground
  641. placedEnemyCharacters.Add(placedEnemy);
  642. }
  643. }
  644. }