using Jovian.EncounterSystem; using Jovian.ZoneSystem; using UnityEngine; namespace Nox.Game { public class EncounterHandler { private readonly ZoneSystem zoneSystem; private readonly EncounterRegistry encounterRegistry; private readonly EncounterView encounterView; private string previousZoneId; private IEncounter activeEncounter; public EncounterHandler(ZoneSystem zoneSystem, EncounterRegistry encounterRegistry, EncounterPrefabs encounterPrefabs) { this.zoneSystem = zoneSystem; this.encounterRegistry = encounterRegistry; encounterView = new EncounterView(encounterPrefabs); encounterView.OptionSelected += OnOptionSelected; } public bool AskForRandomEncounter(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter) { return ResolveEncounter(zoneContext, encounterTableId, out encounter); } public bool AskForRandomEncounterOfType(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter, IEncounterKind encounterKind) { return ResolveEncounter(zoneContext, encounterTableId, out encounter, encounterKind); } public bool AskForEncounter(string encounterId, out IEncounter encounter) { return encounterRegistry.GetEncounters().TryGetValue(encounterId, out encounter); } private bool ResolveEncounter(ZoneContext zoneContext, string encounterTableId, out IEncounter encounter, IEncounterKind encounterKind = null) { encounter = null; if(zoneContext.isSafe) { return false; } var randomChance = Random.Range(0f, 1f); var shouldTrigger = randomChance <= zoneContext.finalEncounterChance; if(!shouldTrigger) { Debug.Log($"Rolled for encounter '{encounterTableId}': {randomChance:F2}/{zoneContext.finalEncounterChance:F2} -> none"); return false; } encounter = encounterKind == null ? encounterRegistry.GetRandomEncounter(encounterTableId) : encounterRegistry.GetRandomEncounter(encounterTableId, encounterKind); var resultName = encounter?.EncounterDefinition?.name ?? "none"; Debug.Log($"Rolled for encounter '{encounterTableId}': {randomChance:F2}/{zoneContext.finalEncounterChance:F2} -> {resultName}"); return encounter != null; } private void VerifyZones(Vector3 position) { var zoneContext = zoneSystem.QueryZone(position); if(string.IsNullOrEmpty(zoneContext.resolvedZoneId)) { return; } var currentZoneId = zoneContext.resolvedZoneId; if(currentZoneId != previousZoneId) { if(!string.IsNullOrEmpty(currentZoneId)) { Debug.Log($"Entered zone: {currentZoneId} (encounter: {zoneContext.encounterTableId}, safe: {zoneContext.isSafe})"); if(ResolveEncounter(zoneContext, zoneContext.encounterTableId, out var encounter)) { TriggerEncounter(encounter); } } else if(!string.IsNullOrEmpty(previousZoneId)) { Debug.Log($"Left zone: {previousZoneId}"); } previousZoneId = currentZoneId; } } private void TriggerEncounter(IEncounter encounter) { switch(encounter.EncounterDefinition.Kind) { case CombatKind: return; default: activeEncounter = encounter; encounterView?.SetCurrentEncounter(encounter); encounterView?.Show(); break; } } private void OnOptionSelected(int optionIndex) { if(activeEncounter == null) { return; } var options = activeEncounter.EncounterDialogOptionSet?.options; if(options == null || optionIndex < 0 || optionIndex >= options.Count) { return; } ResolveOption(activeEncounter, options[optionIndex]); encounterView?.Hide(); activeEncounter = null; } private void ResolveOption(IEncounter encounter, EncounterDialogOption option) { if(option?.events == null) { return; } for(var i = 0; i < option.events.Count; i++) { var encounterEvent = option.events[i]; if(encounterEvent == null) { continue; } switch(encounterEvent) { case ChainToEncounterEvent chain: if(AskForEncounter(chain.nextEncounterId, out var next)) { TriggerEncounter(next); return; } break; case LogEvent log: Debug.Log($"[Encounter '{encounter.EncounterDefinition.id}'] {log.message}"); break; case StartCombatEvent _: case GiveRewardEvent _: Debug.Log($"[Encounter] unhandled event {encounterEvent.GetType().Name}"); break; } } } public void CheckForEncounters(Vector3 position) { VerifyZones(position); } public void Tick() { } public void Dispose() { if(encounterView != null) { encounterView.OptionSelected -= OnOptionSelected; encounterView.Dispose(); } activeEncounter = null; } } }