forked from Shardstone/trail-into-darkness
some work on wiring in the encounters
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class AnswerPrefab : MonoBehaviour {
|
||||
public class AnswerReference : MonoBehaviour {
|
||||
public TextMeshProUGUI number;
|
||||
public TextMeshProUGUI dialogText;
|
||||
public Button button;
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,13 @@ namespace Nox.Game {
|
||||
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) {
|
||||
@@ -37,15 +39,16 @@ namespace Nox.Game {
|
||||
var shouldTrigger = randomChance <= zoneContext.finalEncounterChance;
|
||||
|
||||
if(!shouldTrigger) {
|
||||
Debug.Log($"Rolled for encounter '{encounterTableId}': {randomChance:F2}/{zoneContext.finalEncounterChance:F2} -> none");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(encounterKind == null) {
|
||||
encounter = encounterRegistry.GetRandomEncounter(encounterTableId);
|
||||
return encounter != null;
|
||||
}
|
||||
encounter = encounterKind == null
|
||||
? encounterRegistry.GetRandomEncounter(encounterTableId)
|
||||
: encounterRegistry.GetRandomEncounter(encounterTableId, encounterKind);
|
||||
|
||||
encounter = 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;
|
||||
}
|
||||
|
||||
@@ -76,12 +79,56 @@ namespace Nox.Game {
|
||||
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);
|
||||
}
|
||||
@@ -89,7 +136,11 @@ namespace Nox.Game {
|
||||
public void Tick() { }
|
||||
|
||||
public void Dispose() {
|
||||
// nothing here
|
||||
if(encounterView != null) {
|
||||
encounterView.OptionSelected -= OnOptionSelected;
|
||||
encounterView.Dispose();
|
||||
}
|
||||
activeEncounter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace Nox.Game {
|
||||
[CreateAssetMenu(fileName = "EncounterPrefabs", menuName = "Nox/EncounterPrefabs")]
|
||||
public class EncounterPrefabs : ScriptableObject {
|
||||
public EncounterSet[] encounterSets;
|
||||
public AnswerPrefab answerPrefab;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -14,5 +13,6 @@ namespace Nox.Game {
|
||||
[field: SerializeReference, SubclassSelector]
|
||||
public IEncounterKind encounterKind;
|
||||
public EncounterReference encounterReference;
|
||||
public AnswerReference answerReference;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
using Jovian.EncounterSystem;
|
||||
using Nox.Game.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class EncounterView : IMenuView{
|
||||
private readonly EncounterPrefabs encounterPrefabs;
|
||||
private readonly IEncounterKind encounterKind;
|
||||
private IEncounter currentEncounter;
|
||||
public class EncounterView : IMenuView {
|
||||
private const int MaxAnswers = 4;
|
||||
|
||||
private Dictionary<IEncounterKind, EncounterReference> encounterKindToPrefab = new ();
|
||||
private IEncounterKind currentActiveKind;
|
||||
private readonly EncounterPrefabs encounterPrefabs;
|
||||
private readonly Dictionary<Type, EncounterReference> kindToReference = new();
|
||||
private readonly Dictionary<Type, List<AnswerReference>> kindToAnswerPool = new();
|
||||
|
||||
private IEncounter currentEncounter;
|
||||
private EncounterReference currentReference;
|
||||
private List<AnswerReference> currentAnswerPool;
|
||||
|
||||
public event Action<int> OptionSelected;
|
||||
|
||||
public EncounterView(EncounterPrefabs encounterPrefabs) {
|
||||
this.encounterPrefabs = encounterPrefabs;
|
||||
@@ -19,25 +25,143 @@ namespace Nox.Game {
|
||||
|
||||
public void SetCurrentEncounter(IEncounter encounter) {
|
||||
currentEncounter = encounter;
|
||||
if(!encounterKindToPrefab.TryGetValue(encounter.EncounterDefinition.Kind, out var encounterReference)) {
|
||||
encounterReference = Object.Instantiate(encounterPrefabs.encounterSets.FirstOrDefault(e => e.encounterKind == encounterKind)?.encounterReference);
|
||||
encounterKindToPrefab.Add(encounter.EncounterDefinition.Kind, encounterReference);
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize() { }
|
||||
|
||||
public void Show() {
|
||||
currentActiveKind = currentEncounter.EncounterDefinition.Kind;
|
||||
if(currentEncounter?.EncounterDefinition?.Kind == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentReference) {
|
||||
currentReference.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
var kindType = currentEncounter.EncounterDefinition.Kind.GetType();
|
||||
var set = encounterPrefabs.encounterSets
|
||||
.FirstOrDefault(s => s.encounterKind != null && s.encounterKind.GetType() == kindType);
|
||||
if(set == null || !set.encounterReference) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!kindToReference.TryGetValue(kindType, out var reference) || !reference) {
|
||||
reference = UnityEngine.Object.Instantiate(set.encounterReference);
|
||||
kindToReference[kindType] = reference;
|
||||
}
|
||||
|
||||
currentReference = reference;
|
||||
currentAnswerPool = GetOrBuildAnswerPool(kindType, set);
|
||||
|
||||
PopulateEncounterReference();
|
||||
encounterKindToPrefab[currentActiveKind].gameObject.SetActive(true);
|
||||
}
|
||||
private void PopulateEncounterReference() {
|
||||
currentReference.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Hide() {
|
||||
encounterKindToPrefab[currentActiveKind].gameObject.SetActive(false);
|
||||
if(currentReference) {
|
||||
currentReference.gameObject.SetActive(false);
|
||||
}
|
||||
DeactivateAnswers(currentAnswerPool);
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
|
||||
public void Dispose() {
|
||||
foreach(var reference in kindToReference.Values) {
|
||||
if(reference) {
|
||||
UnityEngine.Object.Destroy(reference.gameObject);
|
||||
}
|
||||
}
|
||||
kindToReference.Clear();
|
||||
kindToAnswerPool.Clear();
|
||||
currentReference = null;
|
||||
currentAnswerPool = null;
|
||||
currentEncounter = null;
|
||||
OptionSelected = null;
|
||||
}
|
||||
|
||||
private List<AnswerReference> GetOrBuildAnswerPool(Type kindType, EncounterSet set) {
|
||||
if(kindToAnswerPool.TryGetValue(kindType, out var pool) && pool != null) {
|
||||
return pool;
|
||||
}
|
||||
|
||||
pool = new List<AnswerReference>(MaxAnswers);
|
||||
kindToAnswerPool[kindType] = pool;
|
||||
|
||||
if(!set.answerReference || !currentReference.encounterOptionsContainer) {
|
||||
return pool;
|
||||
}
|
||||
|
||||
for(var i = 0; i < MaxAnswers; i++) {
|
||||
var answer = UnityEngine.Object.Instantiate(set.answerReference, currentReference.encounterOptionsContainer);
|
||||
answer.gameObject.SetActive(false);
|
||||
pool.Add(answer);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
private void PopulateEncounterReference() {
|
||||
var definition = currentEncounter.EncounterDefinition;
|
||||
var visuals = currentEncounter.EncounterVisuals;
|
||||
|
||||
if(currentReference.encounterName) {
|
||||
currentReference.encounterName.text = definition.name;
|
||||
}
|
||||
if(currentReference.encounterDescription) {
|
||||
currentReference.encounterDescription.text = definition.description;
|
||||
}
|
||||
if(currentReference.encounterArt && visuals != null) {
|
||||
currentReference.encounterArt.sprite = visuals.encounterArt;
|
||||
}
|
||||
|
||||
PopulateAnswers();
|
||||
}
|
||||
|
||||
private void PopulateAnswers() {
|
||||
DeactivateAnswers(currentAnswerPool);
|
||||
|
||||
var optionSet = currentEncounter.EncounterDialogOptionSet;
|
||||
if(currentAnswerPool == null || optionSet?.options == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var count = Mathf.Min(optionSet.options.Count, currentAnswerPool.Count);
|
||||
for(var i = 0; i < count; i++) {
|
||||
var option = optionSet.options[i];
|
||||
var answer = currentAnswerPool[i];
|
||||
if(option == null || !answer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(answer.number) {
|
||||
answer.number.text = (i + 1).ToString();
|
||||
}
|
||||
if(answer.dialogText) {
|
||||
answer.dialogText.text = option.text.Resolve(optionSet.library);
|
||||
}
|
||||
BindAnswerButton(answer, i);
|
||||
answer.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindAnswerButton(AnswerReference answer, int optionIndex) {
|
||||
var button = answer.button ? answer.button : answer.GetComponentInChildren<UnityEngine.UI.Button>(true);
|
||||
if(!button) {
|
||||
return;
|
||||
}
|
||||
button.onClick.RemoveAllListeners();
|
||||
button.onClick.AddListener(() => OptionSelected?.Invoke(optionIndex));
|
||||
}
|
||||
|
||||
private static void DeactivateAnswers(List<AnswerReference> pool) {
|
||||
if(pool == null) {
|
||||
return;
|
||||
}
|
||||
for(var i = 0; i < pool.Count; i++) {
|
||||
if(pool[i]) {
|
||||
pool[i].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user