using UnityEngine;
///
/// Combat encounter events - ambushes, bandits, wild animals, etc.
/// More likely in forests and mountains, less likely on roads
///
[CreateAssetMenu(fileName = "New Combat Event", menuName = "RPG/Travel Events/Combat Event")]
public class CombatTravelEvent : TravelEvent
{
[Header("Combat Event Settings")]
public int minEnemies = 1;
public int maxEnemies = 3;
[Tooltip("Drag EnemyCharacterData assets here")]
public EnemyCharacterData[] possibleEnemies = new EnemyCharacterData[0];
[Header("Escape Configuration")]
public bool allowRunningAway = true;
[Range(0f, 1f)]
public float runAwaySuccessChance = 0.75f;
public int runAwayHealthPenalty = 5;
[Header("Run Away Messages")]
[TextArea(2, 4)]
public string[] successfulRunAwayMessages = {
"Your party successfully escapes from the enemies!",
"Quick thinking allows your party to avoid the confrontation!",
"Your party slips away unnoticed by the enemies."
};
[TextArea(2, 4)]
public string[] failedRunAwayMessages = {
"The enemies catch up to your party! You take {damage} damage while trying to escape.",
"Your escape attempt fails! The enemies pursue and wound your party for {damage} damage.",
"The enemies block your escape route! Your party suffers {damage} damage in the failed attempt."
};
[Header("Combat Event Descriptions")]
[TextArea(2, 4)]
public string[] encounterDescriptions = {
"Your party is ambushed by {enemyType}s!",
"A group of {enemyType}s blocks your path!",
"You stumble upon a {enemyType} camp!"
};
public override EventResult ExecuteEvent(TravelEventContext context)
{
int enemyCount = Random.Range(minEnemies, maxEnemies + 1);
// Ensure we have valid enemies configured
if (possibleEnemies == null || possibleEnemies.Length == 0)
{
Debug.LogError($"No enemies configured for combat event: {eventName}");
return EventResult.NoEvent();
}
// Filter out null entries
var validEnemies = System.Array.FindAll(possibleEnemies, e => e != null);
if (validEnemies.Length == 0)
{
Debug.LogError($"All enemy references are null for combat event: {eventName}");
return EventResult.NoEvent();
}
// Select random enemy
EnemyCharacterData selectedEnemy = validEnemies[Random.Range(0, validEnemies.Length)];
string enemyType = selectedEnemy.enemyName;
// Generate description
string description = encounterDescriptions[Random.Range(0, encounterDescriptions.Length)];
description = description.Replace("{enemyType}", enemyType);
// Try to use combat event integration for popup choice
Debug.Log("🔍 Looking for CombatEventIntegration component...");
// First try to find it by component type
var integrationComponents = FindObjectsByType(FindObjectsSortMode.None);
var combatIntegration = System.Array.Find(integrationComponents,
comp => comp.GetType().Name == "CombatEventIntegration");
if (combatIntegration == null)
{
// Try the reflection approach as fallback
var type = System.Type.GetType("CombatEventIntegration");
if (type != null)
{
combatIntegration = FindFirstObjectByType(type) as MonoBehaviour;
}
}
if (combatIntegration != null)
{
Debug.Log($"✅ Found CombatEventIntegration: {combatIntegration.name}");
// Create battle data for the popup
var battleData = new BattleEventData
{
enemyCount = enemyCount,
enemyType = enemyType,
enemyCharacterData = selectedEnemy
};
// Use reflection to call ShowCombatChoicePopup with the new signature
var method = combatIntegration.GetType().GetMethod("ShowCombatChoicePopup");
if (method != null)
{
Debug.Log($"🎭 Calling ShowCombatChoicePopup with {enemyCount} {enemyType}(s) and combat event reference");
method.Invoke(combatIntegration, new object[] { battleData, context, description, this });
// Return a special result that indicates popup is handling the choice
return new EventResult("Combat encounter detected...")
{
shouldStopTravel = true, // Stop travel while popup is showing
startBattle = false, // Don't start battle yet - popup will handle it
eventOccurred = true
};
}
else
{
Debug.LogError("❌ ShowCombatChoicePopup method not found on CombatEventIntegration");
}
}
else
{
Debug.LogWarning("⚠️ No CombatEventIntegration component found in scene");
}
// Fallback to immediate battle if no integration found
Debug.LogWarning("⚠️ No CombatEventIntegration found, proceeding with immediate battle");
var result = EventResult.SimpleBattle(description, enemyCount, enemyType);
result.battleData.enemyCharacterData = selectedEnemy;
return result;
}
///
/// Handle escape attempt for this specific combat event
///
public EventResult HandleEscapeAttempt(TravelEventContext context)
{
if (!allowRunningAway)
{
Debug.LogWarning($"🚫 Running away is not allowed for this combat event: {eventName}");
return null; // Force battle
}
Debug.Log($"🏃 Processing escape attempt for {eventName} (success chance: {runAwaySuccessChance:P})");
// Roll for escape success
bool escapeSuccessful = Random.value <= runAwaySuccessChance;
if (escapeSuccessful)
{
return CreateSuccessfulEscapeResult();
}
else
{
return CreateFailedEscapeResult(context);
}
}
///
/// Create result for successful escape
///
private EventResult CreateSuccessfulEscapeResult()
{
string message = successfulRunAwayMessages[Random.Range(0, successfulRunAwayMessages.Length)];
Debug.Log($"✅ Escape successful: {message}");
return new EventResult(message)
{
shouldStopTravel = false, // Don't stop travel for successful escape
startBattle = false,
eventOccurred = true
};
}
///
/// Create result for failed escape
///
private EventResult CreateFailedEscapeResult(TravelEventContext context)
{
string message = failedRunAwayMessages[Random.Range(0, failedRunAwayMessages.Length)];
message = message.Replace("{damage}", runAwayHealthPenalty.ToString());
Debug.Log($"❌ Escape failed: {message}");
var result = new EventResult(message)
{
shouldStopTravel = true, // Stop travel for failed escape
startBattle = false, // Don't start battle, just apply penalty
eventOccurred = true,
healthChange = -runAwayHealthPenalty // Apply health penalty through EventResult system
};
return result;
}
void OnEnable()
{
// Set default values for combat events
eventType = EventType.Combat;
rarity = EventRarity.Common;
// Combat events are more likely in dangerous terrain
forestChance = 0.8f;
mountainChance = 0.9f;
plainsChance = 0.4f;
roadChance = 0.2f; // Much less likely on roads
townChance = 0.1f; // Very unlikely in towns
villageChance = 0.3f;
}
}
///
/// Trading encounter events - merchants, traders, caravans
/// More likely on roads and near settlements
///
[CreateAssetMenu(fileName = "New Trading Event", menuName = "RPG/Travel Events/Trading Event")]
public class TradingTravelEvent : TravelEvent
{
[Header("Trading Event Settings")]
public string[] merchantTypes = { "Traveling Merchant", "Caravan Trader", "Wandering Peddler" };
public bool canHaveRareItems = true;
[Range(0f, 1f)]
public float rareItemChance = 0.3f;
[Range(0.5f, 1.5f)]
public float priceModifier = 1f;
[Header("Trading Event Descriptions")]
[TextArea(2, 4)]
public string[] encounterDescriptions = {
"You encounter a {merchantType} on the road.",
"A {merchantType} approaches your party with goods to sell.",
"You come across a {merchantType} resting by the roadside."
};
public override EventResult ExecuteEvent(TravelEventContext context)
{
string merchantType = merchantTypes[Random.Range(0, merchantTypes.Length)];
string description = encounterDescriptions[Random.Range(0, encounterDescriptions.Length)];
description = description.Replace("{merchantType}", merchantType);
var result = EventResult.SimpleTrading(description, merchantType);
result.tradingData.hasRareItems = canHaveRareItems && Random.value < rareItemChance;
result.tradingData.priceModifier = priceModifier;
return result;
}
void OnEnable()
{
// Set default values for trading events
eventType = EventType.Trading;
rarity = EventRarity.Common;
// Trading events are more likely on roads and near settlements
roadChance = 0.9f;
townChance = 0.7f;
villageChance = 0.8f;
bridgeChance = 0.6f; // Common crossing points
ferryChance = 0.5f;
// Less likely in wilderness
forestChance = 0.3f;
mountainChance = 0.2f;
plainsChance = 0.5f;
}
}
///
/// Discovery events - finding treasures, resources, or hidden locations
///
[CreateAssetMenu(fileName = "New Discovery Event", menuName = "RPG/Travel Events/Discovery Event")]
public class DiscoveryTravelEvent : TravelEvent
{
[Header("Discovery Settings")]
public int minGoldFound = 10;
public int maxGoldFound = 100;
public bool canFindItems = true;
[Header("Discovery Descriptions")]
[TextArea(2, 4)]
public string[] discoveryDescriptions = {
"Your party discovers a hidden cache containing {amount} gold!",
"While exploring, you find an abandoned stash with {amount} gold pieces.",
"A keen-eyed party member spots something valuable - {amount} gold!"
};
public override EventResult ExecuteEvent(TravelEventContext context)
{
int goldFound = Random.Range(minGoldFound, maxGoldFound + 1);
string description = discoveryDescriptions[Random.Range(0, discoveryDescriptions.Length)];
description = description.Replace("{amount}", goldFound.ToString());
return new EventResult(description)
{
goldChange = goldFound
};
}
void OnEnable()
{
eventType = EventType.Discovery;
rarity = EventRarity.Uncommon;
// More likely in remote areas
forestChance = 0.7f;
mountainChance = 0.8f;
plainsChance = 0.4f;
roadChance = 0.3f;
townChance = 0.1f;
}
}
///
/// Rest events - safe camping spots, inns, healing springs
///
[CreateAssetMenu(fileName = "New Rest Event", menuName = "RPG/Travel Events/Rest Event")]
public class RestTravelEvent : TravelEvent
{
[Header("Rest Settings")]
public int healthRestored = 25;
public bool restoresAllHealth = false;
[Header("Rest Descriptions")]
[TextArea(2, 4)]
public string[] restDescriptions = {
"Your party finds a peaceful grove perfect for resting and recovers {health} health.",
"A natural spring provides refreshing water, restoring {health} health to your party.",
"Your party discovers a safe camping spot and takes time to tend wounds, recovering {health} health."
};
public override EventResult ExecuteEvent(TravelEventContext context)
{
int actualHealing = restoresAllHealth ? 100 : healthRestored;
string description = restDescriptions[Random.Range(0, restDescriptions.Length)];
description = description.Replace("{health}", actualHealing.ToString());
return new EventResult(description)
{
healthChange = actualHealing
};
}
void OnEnable()
{
eventType = EventType.Rest;
rarity = EventRarity.Common;
// More likely in natural areas
forestChance = 0.8f;
riverChance = 0.9f;
lakeChance = 0.9f;
plainsChance = 0.6f;
mountainChance = 0.5f;
roadChance = 0.4f;
townChance = 0.2f;
}
}
///
/// Hazard events - natural dangers, traps, environmental challenges
///
[CreateAssetMenu(fileName = "New Hazard Event", menuName = "RPG/Travel Events/Hazard Event")]
public class HazardTravelEvent : TravelEvent
{
[Header("Hazard Settings")]
public int minHealthLoss = 5;
public int maxHealthLoss = 20;
public int goldCost = 0; // Cost to avoid the hazard
[Header("Hazard Descriptions")]
[TextArea(2, 4)]
public string[] hazardDescriptions = {
"Your party gets caught in a sudden rockslide, losing {damage} health.",
"Treacherous terrain causes injuries to your party members, resulting in {damage} health loss.",
"A hidden pit trap catches one of your party members, causing {damage} damage."
};
public override EventResult ExecuteEvent(TravelEventContext context)
{
int damage = Random.Range(minHealthLoss, maxHealthLoss + 1);
string description = hazardDescriptions[Random.Range(0, hazardDescriptions.Length)];
description = description.Replace("{damage}", damage.ToString());
return new EventResult(description)
{
healthChange = -damage,
goldChange = -goldCost
};
}
void OnEnable()
{
eventType = EventType.Hazard;
rarity = EventRarity.Common;
// More likely in dangerous terrain
mountainChance = 0.9f;
forestChance = 0.6f;
riverChance = 0.7f;
oceanChance = 0.8f;
// Less likely in safe areas
roadChance = 0.2f;
townChance = 0.1f;
villageChance = 0.2f;
plainsChance = 0.4f;
}
}