TravelEvent.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using UnityEngine;
  2. using System;
  3. /// <summary>
  4. /// Base class for all travel events that can occur during journeys
  5. /// </summary>
  6. [Serializable]
  7. public abstract class TravelEvent : ScriptableObject
  8. {
  9. [Header("Basic Event Info")]
  10. public string eventName;
  11. [TextArea(3, 6)]
  12. public string eventDescription;
  13. public EventType eventType;
  14. public EventRarity rarity = EventRarity.Common;
  15. [Header("Terrain Preferences")]
  16. [Range(0f, 1f)]
  17. public float plainsChance = 0.5f;
  18. [Range(0f, 1f)]
  19. public float forestChance = 0.5f;
  20. [Range(0f, 1f)]
  21. public float mountainChance = 0.5f;
  22. [Range(0f, 1f)]
  23. public float roadChance = 0.5f;
  24. [Range(0f, 1f)]
  25. public float riverChance = 0.5f;
  26. [Range(0f, 1f)]
  27. public float lakeChance = 0.5f;
  28. [Range(0f, 1f)]
  29. public float oceanChance = 0.5f;
  30. [Header("Feature Preferences")]
  31. [Range(0f, 1f)]
  32. public float townChance = 0.5f;
  33. [Range(0f, 1f)]
  34. public float villageChance = 0.5f;
  35. [Range(0f, 1f)]
  36. public float bridgeChance = 0.5f;
  37. [Range(0f, 1f)]
  38. public float tunnelChance = 0.5f;
  39. [Range(0f, 1f)]
  40. public float ferryChance = 0.5f;
  41. [Header("Timing")]
  42. public bool canOccurMultipleTimes = true;
  43. public float cooldownDays = 0f; // Days before this event can occur again
  44. /// <summary>
  45. /// Calculate the chance of this event occurring on a specific tile
  46. /// </summary>
  47. public virtual float GetEventChance(MapTile tile)
  48. {
  49. float baseChance = GetBaseChanceForRarity();
  50. float terrainModifier = GetTerrainModifier(tile.terrainType);
  51. float featureModifier = GetFeatureModifier(tile.featureType);
  52. return baseChance * terrainModifier * featureModifier;
  53. }
  54. /// <summary>
  55. /// Execute the event - must be implemented by derived classes
  56. /// </summary>
  57. public abstract EventResult ExecuteEvent(TravelEventContext context);
  58. /// <summary>
  59. /// Check if this event can occur given the current context
  60. /// </summary>
  61. public virtual bool CanOccur(TravelEventContext context)
  62. {
  63. // Check cooldown
  64. if (!canOccurMultipleTimes && context.eventHistory.HasOccurred(this))
  65. {
  66. return false;
  67. }
  68. if (cooldownDays > 0f && context.eventHistory.GetTimeSinceLastOccurrence(this) < cooldownDays)
  69. {
  70. return false;
  71. }
  72. return true;
  73. }
  74. private float GetBaseChanceForRarity()
  75. {
  76. return rarity switch
  77. {
  78. EventRarity.VeryCommon => 0.25f,
  79. EventRarity.Common => 0.15f,
  80. EventRarity.Uncommon => 0.08f,
  81. EventRarity.Rare => 0.04f,
  82. EventRarity.VeryRare => 0.02f,
  83. EventRarity.Legendary => 0.005f,
  84. _ => 0.1f
  85. };
  86. }
  87. private float GetTerrainModifier(TerrainType terrain)
  88. {
  89. return terrain switch
  90. {
  91. TerrainType.Plains => plainsChance,
  92. TerrainType.Forest => forestChance,
  93. TerrainType.Mountain => mountainChance,
  94. TerrainType.River => riverChance,
  95. TerrainType.Lake => lakeChance,
  96. TerrainType.Ocean => oceanChance,
  97. TerrainType.ForestRiver => forestChance * riverChance, // Hybrid terrain
  98. _ => 0.5f
  99. };
  100. }
  101. private float GetFeatureModifier(FeatureType feature)
  102. {
  103. return feature switch
  104. {
  105. FeatureType.Road => roadChance,
  106. FeatureType.Town => townChance,
  107. FeatureType.Village => villageChance,
  108. FeatureType.Bridge => bridgeChance,
  109. FeatureType.Tunnel => tunnelChance,
  110. FeatureType.Ferry => ferryChance,
  111. FeatureType.None => 1f, // No modifier for no feature
  112. _ => 0.5f
  113. };
  114. }
  115. }
  116. [Serializable]
  117. public enum EventType
  118. {
  119. Combat, // Battle encounters
  120. Trading, // Merchant encounters
  121. Discovery, // Finding items/resources
  122. Social, // Meeting NPCs, getting information
  123. Hazard, // Environmental dangers
  124. Rest, // Camping, healing opportunities
  125. Mystery // Strange occurrences, puzzles
  126. }
  127. [Serializable]
  128. public enum EventRarity
  129. {
  130. VeryCommon, // 25% base chance
  131. Common, // 15% base chance
  132. Uncommon, // 8% base chance
  133. Rare, // 4% base chance
  134. VeryRare, // 2% base chance
  135. Legendary // 0.5% base chance
  136. }
  137. /// <summary>
  138. /// Result of executing a travel event
  139. /// </summary>
  140. [Serializable]
  141. public class EventResult
  142. {
  143. public bool eventOccurred = true;
  144. public bool shouldStopTravel = false;
  145. public bool startBattle = false;
  146. public bool openTrading = false;
  147. public string resultMessage = "";
  148. // Resource changes
  149. public int goldChange = 0;
  150. public int foodChange = 0;
  151. public int healthChange = 0;
  152. // Battle setup (if startBattle is true)
  153. public BattleEventData battleData;
  154. // Trading setup (if openTrading is true)
  155. public TradingEventData tradingData;
  156. public EventResult(string message)
  157. {
  158. resultMessage = message;
  159. }
  160. public static EventResult NoEvent()
  161. {
  162. return new EventResult("") { eventOccurred = false };
  163. }
  164. public static EventResult SimpleBattle(string message, int enemyCount, string enemyType = "Bandit")
  165. {
  166. return new EventResult(message)
  167. {
  168. shouldStopTravel = true,
  169. startBattle = true,
  170. battleData = new BattleEventData
  171. {
  172. enemyCount = enemyCount,
  173. enemyType = enemyType
  174. }
  175. };
  176. }
  177. public static EventResult SimpleTrading(string message, string merchantType = "Traveling Merchant")
  178. {
  179. return new EventResult(message)
  180. {
  181. shouldStopTravel = true,
  182. openTrading = true,
  183. tradingData = new TradingEventData
  184. {
  185. merchantType = merchantType,
  186. hasRareItems = UnityEngine.Random.value < 0.3f
  187. }
  188. };
  189. }
  190. }
  191. [Serializable]
  192. public class BattleEventData
  193. {
  194. public int enemyCount = 1;
  195. public string enemyType = "Bandit";
  196. public string battleDescription = "";
  197. [Tooltip("Reference to the actual enemy data asset (safer than string names)")]
  198. public EnemyCharacterData enemyCharacterData = null;
  199. }
  200. [Serializable]
  201. public class TradingEventData
  202. {
  203. public string merchantType = "Traveling Merchant";
  204. public bool hasRareItems = false;
  205. public float priceModifier = 1f; // 1f = normal prices, 0.8f = 20% discount, etc.
  206. }