TravelEventSystem.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. /// <summary>
  5. /// Main travel event system that manages when and where events occur during travel
  6. /// Integrates with the existing TeamTravelSystem
  7. /// </summary>
  8. public class TravelEventSystem : MonoBehaviour
  9. {
  10. [Header("Event System Settings")]
  11. public bool enableEvents = true;
  12. [Range(0f, 1f)]
  13. public float baseEventChance = 0.1f; // 10% chance per tile check (reduced from 15%)
  14. [Range(1, 10)]
  15. public int tilesPerEventCheck = 4; // Check for events every 4 tiles (increased from 3)
  16. [Header("Event Collections")]
  17. public List<TravelEvent> availableEvents = new List<TravelEvent>();
  18. [Header("Debug")]
  19. public bool showDebugLogs = false;
  20. public bool forceNextEvent = false; // For testing
  21. // Event tracking
  22. private TravelEventHistory globalEventHistory;
  23. private int tilesTraveledSinceLastCheck = 0;
  24. private TravelEventContext currentContext;
  25. private Vector2Int lastTeamPosition = Vector2Int.zero;
  26. private bool hasInitializedPosition = false;
  27. // Component references
  28. private TeamTravelSystem travelSystem;
  29. private MapMaker2 mapMaker;
  30. private SimpleTeamPlacement teamPlacement;
  31. private TravelEventUI eventUI;
  32. private MonoBehaviour markerVisualizer; // Use MonoBehaviour to avoid compilation issues
  33. // Enhanced system will be linked after compilation
  34. private object enhancedEventSystem;
  35. void Start()
  36. {
  37. // Find required components
  38. travelSystem = FindFirstObjectByType<TeamTravelSystem>();
  39. mapMaker = FindFirstObjectByType<MapMaker2>();
  40. teamPlacement = FindFirstObjectByType<SimpleTeamPlacement>();
  41. eventUI = FindFirstObjectByType<TravelEventUI>();
  42. // Find EventMarkerVisualizer using reflection to avoid compilation order issues
  43. var markerVisualizerComponents = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None);
  44. markerVisualizer = System.Array.Find(markerVisualizerComponents,
  45. comp => comp.GetType().Name == "EventMarkerVisualizer");
  46. // Enhanced system will be found after compilation
  47. // enhancedEventSystem = FindFirstObjectByType<EnhancedTravelEventSystem>();
  48. globalEventHistory = new TravelEventHistory();
  49. if (showDebugLogs)
  50. {
  51. if (eventUI == null)
  52. Debug.LogWarning("⚠️ TravelEventUI not found. Event messages will only appear in console.");
  53. LogEventDistribution();
  54. }
  55. // Load default events if none are assigned
  56. if (availableEvents.Count == 0)
  57. {
  58. LoadDefaultEvents();
  59. }
  60. }
  61. void Update()
  62. {
  63. if (!enableEvents || travelSystem == null) return;
  64. // Track actual tile movement instead of frame-based checks
  65. Vector2Int currentTeamPosition = GetCurrentTeamPosition();
  66. if (!hasInitializedPosition)
  67. {
  68. lastTeamPosition = currentTeamPosition;
  69. hasInitializedPosition = true;
  70. return;
  71. }
  72. // Only check for events when the team actually moves to a new tile
  73. if (currentTeamPosition != lastTeamPosition)
  74. {
  75. tilesTraveledSinceLastCheck++;
  76. if (showDebugLogs)
  77. {
  78. Debug.Log($"🚶 Team moved from {lastTeamPosition} to {currentTeamPosition} (tiles since last check: {tilesTraveledSinceLastCheck})");
  79. }
  80. // Check for event marker triggers first
  81. CheckForEventMarkerTriggers(currentTeamPosition);
  82. lastTeamPosition = currentTeamPosition;
  83. // Check for events every N tiles traveled
  84. if (tilesTraveledSinceLastCheck >= tilesPerEventCheck)
  85. {
  86. if (showDebugLogs)
  87. {
  88. Debug.Log($"🎲 Checking for travel event after {tilesTraveledSinceLastCheck} tiles traveled");
  89. }
  90. CheckForTravelEvent();
  91. tilesTraveledSinceLastCheck = 0;
  92. }
  93. }
  94. }
  95. /// <summary>
  96. /// Main method to check if a travel event should occur
  97. /// </summary>
  98. public void CheckForTravelEvent()
  99. {
  100. if (!enableEvents) return;
  101. // Get current travel context
  102. currentContext = CreateCurrentContext();
  103. if (currentContext == null) return;
  104. // Calculate if an event should occur
  105. float eventRoll = Random.value;
  106. float eventThreshold = CalculateEventThreshold(currentContext);
  107. // Force event for testing
  108. if (forceNextEvent)
  109. {
  110. forceNextEvent = false;
  111. eventRoll = 0f; // Guarantee event
  112. eventThreshold = 1f;
  113. }
  114. if (eventRoll <= eventThreshold)
  115. {
  116. TriggerRandomEvent(currentContext);
  117. }
  118. }
  119. /// <summary>
  120. /// Force a specific event to occur (for testing or story purposes)
  121. /// </summary>
  122. public void TriggerSpecificEvent(TravelEvent eventToTrigger)
  123. {
  124. if (eventToTrigger == null) return;
  125. currentContext = CreateCurrentContext();
  126. if (currentContext == null) return;
  127. ExecuteEvent(eventToTrigger, currentContext);
  128. }
  129. /// <summary>
  130. /// Check if team has triggered any event markers
  131. /// </summary>
  132. private void CheckForEventMarkerTriggers(Vector2Int teamPosition)
  133. {
  134. if (markerVisualizer == null) return;
  135. // Use reflection to call CheckForMarkerTrigger method
  136. var method = markerVisualizer.GetType().GetMethod("CheckForMarkerTrigger");
  137. if (method != null)
  138. {
  139. var triggeredEvent = method.Invoke(markerVisualizer, new object[] { teamPosition }) as TravelEvent;
  140. if (triggeredEvent != null)
  141. {
  142. // Create context and execute the triggered event
  143. currentContext = CreateCurrentContext();
  144. if (currentContext != null)
  145. {
  146. ExecuteEvent(triggeredEvent, currentContext);
  147. }
  148. }
  149. }
  150. }
  151. /// <summary>
  152. /// Trigger a random event based on current context
  153. /// </summary>
  154. private void TriggerRandomEvent(TravelEventContext context)
  155. {
  156. var possibleEvents = GetPossibleEvents(context);
  157. if (possibleEvents.Count == 0)
  158. {
  159. if (showDebugLogs)
  160. Debug.Log("🎲 No valid events found for current context");
  161. return;
  162. }
  163. // Separate events by trigger type
  164. var automaticEvents = possibleEvents.Where(e => e.triggerType == EventTriggerType.Automatic).ToList();
  165. var spottableEvents = possibleEvents.Where(e => e.triggerType == EventTriggerType.Spottable).ToList();
  166. // Try to trigger automatic event first
  167. if (automaticEvents.Count > 0)
  168. {
  169. TravelEvent selectedEvent = SelectWeightedEvent(automaticEvents, context);
  170. if (selectedEvent != null)
  171. {
  172. ExecuteEvent(selectedEvent, context);
  173. return;
  174. }
  175. }
  176. // Try to spawn spottable event markers
  177. if (spottableEvents.Count > 0 && markerVisualizer != null)
  178. {
  179. TravelEvent selectedSpottableEvent = SelectWeightedEvent(spottableEvents, context);
  180. if (selectedSpottableEvent != null)
  181. {
  182. // Use reflection to call TrySpawnEventMarker method
  183. var spawnMethod = markerVisualizer.GetType().GetMethod("TrySpawnEventMarker");
  184. if (spawnMethod != null)
  185. {
  186. var markerSpawned = (bool)spawnMethod.Invoke(markerVisualizer, new object[] { selectedSpottableEvent });
  187. if (markerSpawned && showDebugLogs)
  188. {
  189. Debug.Log($"🔴 Spawned spottable event marker: {selectedSpottableEvent.eventName}");
  190. }
  191. }
  192. }
  193. }
  194. }
  195. /// <summary>
  196. /// Execute a travel event and handle its results
  197. /// </summary>
  198. private void ExecuteEvent(TravelEvent travelEvent, TravelEventContext context)
  199. {
  200. if (showDebugLogs)
  201. {
  202. Debug.Log($"🎭 Executing event: {travelEvent.eventName} at {context.currentPosition}");
  203. }
  204. // Execute the event
  205. EventResult result = travelEvent.ExecuteEvent(context);
  206. if (!result.eventOccurred)
  207. {
  208. if (showDebugLogs)
  209. Debug.Log($"🎭 Event {travelEvent.eventName} chose not to occur");
  210. return;
  211. }
  212. // Record the event
  213. globalEventHistory.RecordEvent(travelEvent, context);
  214. // Display event message (unless suppressed by popup system)
  215. if (!result.suppressMessage)
  216. {
  217. if (eventUI != null)
  218. {
  219. eventUI.ShowEventResult(result);
  220. }
  221. else
  222. {
  223. ShowEventMessage(result.resultMessage);
  224. }
  225. }
  226. // Handle the event result
  227. HandleEventResult(result, context);
  228. }
  229. /// <summary>
  230. /// Handle the results of a travel event
  231. /// </summary>
  232. private void HandleEventResult(EventResult result, TravelEventContext context)
  233. {
  234. // Apply resource changes
  235. ApplyResourceChanges(result);
  236. // Handle special event types
  237. if (result.shouldStopTravel)
  238. {
  239. if (travelSystem != null)
  240. {
  241. // Stop current travel using the existing cancellation system
  242. travelSystem.CancelJourney();
  243. Debug.Log("🛑 Travel stopped due to event");
  244. }
  245. }
  246. if (result.startBattle)
  247. {
  248. HandleBattleEvent(result.battleData, context);
  249. }
  250. if (result.openTrading)
  251. {
  252. HandleTradingEvent(result.tradingData, context);
  253. }
  254. }
  255. /// <summary>
  256. /// Create travel event context from current game state
  257. /// </summary>
  258. private TravelEventContext CreateCurrentContext()
  259. {
  260. if (teamPlacement == null || mapMaker == null || travelSystem == null)
  261. return null;
  262. Vector2Int currentPos = teamPlacement.GetCurrentTeamPosition();
  263. var mapData = mapMaker.GetMapData();
  264. var currentTile = mapData.GetTile(currentPos.x, currentPos.y);
  265. var currentRoute = travelSystem.GetCurrentRoute();
  266. var context = new TravelEventContext(currentPos, currentTile, currentRoute)
  267. {
  268. dayOfJourney = 1, // This could be tracked elsewhere
  269. timeOfDay = 12f, // This could be from a day/night system
  270. teamGold = 100, // This should come from actual team resources
  271. teamFood = 50,
  272. eventHistory = globalEventHistory
  273. };
  274. // Set travel context
  275. if (currentRoute != null)
  276. {
  277. context.destination = travelSystem.GetPlannedDestination() ?? currentPos;
  278. context.isOnMainRoad = currentTile.featureType == FeatureType.Road;
  279. }
  280. return context;
  281. }
  282. /// <summary>
  283. /// Calculate the threshold for events to occur based on context
  284. /// </summary>
  285. private float CalculateEventThreshold(TravelEventContext context)
  286. {
  287. float threshold = baseEventChance;
  288. // Modify based on terrain (some areas are more eventful)
  289. switch (context.currentTile.terrainType)
  290. {
  291. case TerrainType.Forest:
  292. threshold *= 1.3f; // More events in forests
  293. break;
  294. case TerrainType.Mountain:
  295. threshold *= 1.4f; // Even more in mountains
  296. break;
  297. case TerrainType.Plains:
  298. threshold *= 0.8f; // Fewer in plains
  299. break;
  300. }
  301. // Modify based on features
  302. switch (context.currentTile.featureType)
  303. {
  304. case FeatureType.Road:
  305. threshold *= 0.7f; // Fewer events on roads (safer travel)
  306. break;
  307. case FeatureType.Town:
  308. case FeatureType.Village:
  309. threshold *= 0.5f; // Much fewer in settlements
  310. break;
  311. }
  312. return Mathf.Clamp01(threshold);
  313. }
  314. /// <summary>
  315. /// Get all events that can occur in the current context
  316. /// </summary>
  317. private List<TravelEvent> GetPossibleEvents(TravelEventContext context)
  318. {
  319. return availableEvents.Where(e => e != null && e.CanOccur(context)).ToList();
  320. }
  321. /// <summary>
  322. /// Select an event based on weighted probabilities
  323. /// </summary>
  324. private TravelEvent SelectWeightedEvent(List<TravelEvent> events, TravelEventContext context)
  325. {
  326. if (events.Count == 0) return null;
  327. if (events.Count == 1) return events[0];
  328. // Calculate weights
  329. var weights = events.Select(e => e.GetEventChance(context.currentTile)).ToList();
  330. float totalWeight = weights.Sum();
  331. if (totalWeight <= 0) return null;
  332. // Select based on weight
  333. float randomValue = Random.value * totalWeight;
  334. float currentWeight = 0f;
  335. for (int i = 0; i < events.Count; i++)
  336. {
  337. currentWeight += weights[i];
  338. if (randomValue <= currentWeight)
  339. {
  340. return events[i];
  341. }
  342. }
  343. return events.Last(); // Fallback
  344. }
  345. /// <summary>
  346. /// Apply resource changes from event results
  347. /// </summary>
  348. private void ApplyResourceChanges(EventResult result)
  349. {
  350. if (result.goldChange != 0)
  351. {
  352. // Distribute gold to team members equally
  353. DistributeGoldToTeam(result.goldChange);
  354. }
  355. if (result.healthChange != 0)
  356. {
  357. // Apply health change to team
  358. // This would integrate with your character health system
  359. Debug.Log($"❤️ Health changed by {result.healthChange}");
  360. }
  361. if (result.foodChange != 0)
  362. {
  363. // Apply food change
  364. Debug.Log($"🍖 Food changed by {result.foodChange}");
  365. }
  366. }
  367. /// <summary>
  368. /// Handle battle events by setting up battle data
  369. /// </summary>
  370. private void HandleBattleEvent(BattleEventData battleData, TravelEventContext context)
  371. {
  372. if (battleData == null) return;
  373. // Try to use enhanced event system for player choice popup
  374. var enhancedSystem = FindFirstObjectByType(System.Type.GetType("EnhancedTravelEventSystem"));
  375. if (enhancedSystem != null)
  376. {
  377. Debug.Log("🎭 Using Enhanced Travel Event System for combat popup");
  378. // Use reflection to call the enhanced handler
  379. var method = enhancedSystem.GetType().GetMethod("HandleEnhancedBattleEvent");
  380. if (method != null)
  381. {
  382. string eventDescription = $"Your party encounters {battleData.enemyCount} {battleData.enemyType}!";
  383. method.Invoke(enhancedSystem, new object[] { battleData, context, eventDescription });
  384. return;
  385. }
  386. }
  387. // Fallback to original battle handling
  388. Debug.Log($"⚔️ Setting up battle: {battleData.enemyCount} {battleData.enemyType}(s)");
  389. // Enhanced battle setup using EnemyCharacterData if available
  390. if (battleData.enemyCharacterData != null)
  391. {
  392. Debug.Log($"🎯 Using enemy data: {battleData.enemyCharacterData.enemyName}");
  393. Debug.Log($"📊 Enemy stats: HP={battleData.enemyCharacterData.maxHealth}, " +
  394. $"AC={battleData.enemyCharacterData.armorClass}, " +
  395. $"Threat={battleData.enemyCharacterData.threatLevel}");
  396. // TODO: Enhanced battle setup with actual enemy data
  397. /*
  398. BattleSetupData.enemySelections.Clear();
  399. for (int i = 0; i < battleData.enemyCount; i++)
  400. {
  401. var enemyData = battleData.enemyCharacterData;
  402. BattleSetupData.enemySelections.Add(new CharacterSelection
  403. {
  404. characterName = $"{enemyData.enemyName}_{i+1}",
  405. weaponType = enemyData.preferredWeapon != null ? enemyData.preferredWeapon.weaponType.ToString() : "Sword",
  406. // Could also include:
  407. // health = enemyData.maxHealth,
  408. // armorClass = enemyData.armorClass,
  409. // threatLevel = enemyData.threatLevel
  410. });
  411. }
  412. */
  413. }
  414. else
  415. {
  416. // Fallback to string-based system
  417. Debug.Log("⚠️ No EnemyCharacterData found, using legacy string-based setup");
  418. /*
  419. BattleSetupData.enemySelections.Clear();
  420. for (int i = 0; i < battleData.enemyCount; i++)
  421. {
  422. BattleSetupData.enemySelections.Add(new CharacterSelection
  423. {
  424. characterName = $"{battleData.enemyType}_{i+1}",
  425. weaponType = "Sword" // Could be randomized
  426. });
  427. }
  428. */
  429. }
  430. }
  431. /// <summary>
  432. /// Handle trading events by opening shop interface
  433. /// </summary>
  434. private void HandleTradingEvent(TradingEventData tradingData, TravelEventContext context)
  435. {
  436. if (tradingData == null) return;
  437. Debug.Log($"🛒 Opening trading with {tradingData.merchantType}");
  438. // This would open your shop system
  439. // You could modify shop inventory based on merchantType and hasRareItems
  440. }
  441. /// <summary>
  442. /// Display event message to player
  443. /// </summary>
  444. private void ShowEventMessage(string message)
  445. {
  446. if (string.IsNullOrEmpty(message)) return;
  447. Debug.Log($"📜 EVENT: {message}");
  448. // Use UI system if available
  449. if (eventUI != null)
  450. {
  451. eventUI.ShowEventMessage(message);
  452. }
  453. }
  454. /// <summary>
  455. /// Load default events if none are assigned in inspector
  456. /// </summary>
  457. private void LoadDefaultEvents()
  458. {
  459. // Load default events from Resources folder
  460. TravelEvent[] defaultEvents = Resources.LoadAll<TravelEvent>("TravelEvents");
  461. availableEvents.AddRange(defaultEvents);
  462. if (showDebugLogs)
  463. {
  464. Debug.Log($"🔄 Loaded {defaultEvents.Length} default events from Resources");
  465. }
  466. }
  467. /// <summary>
  468. /// Debug method to show event distribution
  469. /// </summary>
  470. private void LogEventDistribution()
  471. {
  472. if (!showDebugLogs) return;
  473. var eventsByType = availableEvents.GroupBy(e => e.eventType);
  474. foreach (var group in eventsByType)
  475. {
  476. Debug.Log($"📊 {group.Key}: {group.Count()} events");
  477. }
  478. }
  479. /// <summary>
  480. /// Public method to trigger event check manually (for testing)
  481. /// </summary>
  482. [ContextMenu("Trigger Event Check")]
  483. public void TriggerEventCheck()
  484. {
  485. forceNextEvent = true;
  486. CheckForTravelEvent();
  487. }
  488. /// <summary>
  489. /// Reset event history (useful for testing)
  490. /// </summary>
  491. [ContextMenu("Reset Event History")]
  492. public void ResetEventHistory()
  493. {
  494. globalEventHistory = new TravelEventHistory();
  495. tilesTraveledSinceLastCheck = 0;
  496. Debug.Log("🔄 Event history reset");
  497. }
  498. /// <summary>
  499. /// Get the current team position in tile coordinates
  500. /// </summary>
  501. private Vector2Int GetCurrentTeamPosition()
  502. {
  503. if (teamPlacement == null)
  504. return Vector2Int.zero;
  505. var teamMarker = teamPlacement.GetTeamMarker();
  506. if (teamMarker == null)
  507. return Vector2Int.zero;
  508. // Convert world position to tile position
  509. Vector3 worldPos = teamMarker.transform.position;
  510. return new Vector2Int(
  511. Mathf.RoundToInt(worldPos.x),
  512. Mathf.RoundToInt(worldPos.z)
  513. );
  514. }
  515. #region Gold Distribution System
  516. /// <summary>
  517. /// Distribute gold equally among all team members
  518. /// </summary>
  519. private void DistributeGoldToTeam(int totalGold)
  520. {
  521. if (totalGold <= 0)
  522. {
  523. Debug.LogWarning("Attempted to distribute non-positive gold amount");
  524. return;
  525. }
  526. // Get team size from PlayerPrefs
  527. int teamSize = PlayerPrefs.GetInt("TeamSize", 0);
  528. if (teamSize <= 0)
  529. {
  530. Debug.LogWarning("No team members found to distribute gold to");
  531. return;
  532. }
  533. // Calculate gold per member and remainder
  534. int goldPerMember = totalGold / teamSize;
  535. int remainderGold = totalGold % teamSize;
  536. Debug.Log($"💰 Distributing {totalGold} gold among {teamSize} team members ({goldPerMember} each, {remainderGold} remainder)");
  537. // Distribute gold to each team member
  538. for (int i = 0; i < teamSize; i++)
  539. {
  540. var character = LoadCharacterFromPlayerPrefs(i);
  541. if (character != null)
  542. {
  543. // Add base gold to each member
  544. character.gold += goldPerMember;
  545. // Give remainder gold to first few members
  546. if (i < remainderGold)
  547. {
  548. character.gold += 1;
  549. }
  550. // Handle currency conversion (100 copper = 1 silver, 100 silver = 1 gold)
  551. ConvertCurrency(character);
  552. SaveCharacterToPlayerPrefs(character, i);
  553. Debug.Log($"💰 {character.name}: +{goldPerMember + (i < remainderGold ? 1 : 0)} gold (Total: {character.gold}g {character.silver}s {character.copper}c)");
  554. }
  555. }
  556. Debug.Log($"✅ Gold distribution complete: {totalGold} gold distributed to team");
  557. }
  558. /// <summary>
  559. /// Load character data from PlayerPrefs
  560. /// </summary>
  561. private TeamCharacter LoadCharacterFromPlayerPrefs(int index)
  562. {
  563. string charName = PlayerPrefs.GetString($"Character{index}_Name", "");
  564. if (string.IsNullOrEmpty(charName))
  565. return null;
  566. var character = new TeamCharacter();
  567. character.name = charName;
  568. character.gold = PlayerPrefs.GetInt($"Character{index}_Gold", 0);
  569. character.silver = PlayerPrefs.GetInt($"Character{index}_Silver", 0);
  570. character.copper = PlayerPrefs.GetInt($"Character{index}_Copper", 0);
  571. return character;
  572. }
  573. /// <summary>
  574. /// Save character data to PlayerPrefs
  575. /// </summary>
  576. private void SaveCharacterToPlayerPrefs(TeamCharacter character, int index)
  577. {
  578. PlayerPrefs.SetString($"Character{index}_Name", character.name);
  579. PlayerPrefs.SetInt($"Character{index}_Gold", character.gold);
  580. PlayerPrefs.SetInt($"Character{index}_Silver", character.silver);
  581. PlayerPrefs.SetInt($"Character{index}_Copper", character.copper);
  582. PlayerPrefs.Save();
  583. }
  584. /// <summary>
  585. /// Convert currency (100 copper = 1 silver, 100 silver = 1 gold)
  586. /// </summary>
  587. private void ConvertCurrency(TeamCharacter character)
  588. {
  589. // Convert copper to silver
  590. if (character.copper >= 100)
  591. {
  592. int newSilver = character.copper / 100;
  593. character.silver += newSilver;
  594. character.copper %= 100;
  595. }
  596. // Convert silver to gold
  597. if (character.silver >= 100)
  598. {
  599. int newGold = character.silver / 100;
  600. character.gold += newGold;
  601. character.silver %= 100;
  602. }
  603. }
  604. #endregion
  605. }