Added part of the encounter triggering system

This commit is contained in:
Sebastian Bularca
2026-04-27 00:01:15 +02:00
parent f117ddb914
commit ea6c28bfba
28 changed files with 20336 additions and 185 deletions

View File

@@ -1,4 +1,5 @@
using Jovian.Calendar;
using Jovian.EncounterSystem;
using Jovian.PopupSystem;
using Jovian.PopupSystem.UI;
using Jovian.SaveSystem;
@@ -43,6 +44,9 @@ namespace Nox.Game {
private PartyInventoryHandler partyInventoryHandler;
private PartyGuiView partyGuiView;
private IPopupSystem popupSystem;
private EncounterRegistry encounterRegistry;
private EncounterHandler encounterHandler;
private EncounterPrefabs encounterPrefabs;
public AdventurePlayMode(
PlatformSettings platformSettings,
@@ -103,7 +107,9 @@ namespace Nox.Game {
Debug.LogWarning("AdventurePlayMode started from the Adventure Scene. Loading the last Autosave");
}
encounterRegistry ??= Addressables.LoadAssetAsync<EncounterRegistry>("EncounterRegistry").WaitForCompletion();
scenePrefabs ??= Addressables.LoadAssetAsync<AdventureModePrefabs>("AdventureMapPrefabs").WaitForCompletion();
encounterPrefabs = Addressables.LoadAssetAsync<EncounterPrefabs>("EncounterPrefabs").WaitForCompletion();
mapRef ??= Object.FindFirstObjectByType<MapReference>();
partyRef ??= Object.FindFirstObjectByType<PartyReference>();
if(partyRef && gameDataState.savedPartyPosition.HasValue) {
@@ -129,9 +135,17 @@ namespace Nox.Game {
var calendarSettings = Addressables.LoadAssetAsync<CalendarSettings>("CalendarSettings").WaitForCompletion();
var worldClock = new WorldClock(calendarSettings);
timeHandler ??= new TimeHandler(adventureSettings, adventureData, worldClock);
zoneSystem ??= new ZoneSystem(mapRef.zonesObjectHolder);
partyMovementHandler ??= new PartyMovementHandler(partyRef, cameraController, mapLocationsReference, platformSettings.inputSettings, zoneSystem, adventureData, adventureSettings);
zoneSystem ??= new ZoneSystem(mapRef.zonesObjectHolder);
encounterHandler = new EncounterHandler(zoneSystem, encounterRegistry, encounterPrefabs, adventureData);
partyMovementHandler ??= new PartyMovementHandler(
partyRef,
cameraController,
mapLocationsReference,
platformSettings.inputSettings,
encounterHandler,
adventureData,
adventureSettings);
partyMovementHandler.Initialize();
guiReferences ??= Object.FindFirstObjectByType<GuiReferences>();
@@ -164,6 +178,7 @@ namespace Nox.Game {
timeHandler.Tick();
partyInventoryHandler.Tick();
partyMovementHandler.Tick();
encounterHandler.Tick();
adventureView.Tick();
partyGuiView?.Tick();
popupSystem?.Tick(Time.deltaTime);
@@ -191,10 +206,14 @@ namespace Nox.Game {
inputActions.UI.PauseMenu.Disable();
}
public void Dispose() {
cameraController?.Dispose();
partyMovementHandler?.Dispose();
partyGuiView?.Dispose();
popupSystem?.Dispose();
cameraController?.Dispose();
partyMovementHandler?.Dispose();
encounterHandler?.Dispose();
encounterRegistry = null;
Resources.UnloadUnusedAssets();
}
}

View File

@@ -0,0 +1,9 @@
using TMPro;
using UnityEngine;
namespace Nox.Game {
public class AnswerPrefab : MonoBehaviour {
public TextMeshProUGUI number;
public TextMeshProUGUI dialogText;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c14350aeeed44a28d98d22c6ef048dc
timeCreated: 1777235448

View File

@@ -1,7 +1,100 @@
using System;
using Jovian.EncounterSystem;
using Jovian.ZoneSystem;
using UnityEngine;
namespace Nox.Game {
public class EncounterHandler {
private readonly ZoneSystem zoneSystem;
private readonly EncounterRegistry encounterRegistry;
private readonly AdventureData adventureData;
private readonly EncounterView encounterView;
private string previousZoneId;
private int previousDay;
public EncounterHandler(ZoneSystem zoneSystem, EncounterRegistry encounterRegistry, EncounterPrefabs encounterPrefabs, AdventureData adventureData) {
this.zoneSystem = zoneSystem;
this.encounterRegistry = encounterRegistry;
this.adventureData = adventureData;
encounterView = new EncounterView(encounterPrefabs);
}
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) {
return false;
}
if(encounterKind == null) {
encounter = encounterRegistry.GetRandomEncounter(encounterTableId);
return encounter != null;
}
encounter = encounterRegistry.GetRandomEncounter(encounterTableId, encounterKind);
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, currentZoneId, 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:
encounterView?.SetCurrentEncounter(encounter);
encounterView?.Show();
break;
}
}
public void CheckForEncounters(Vector3 position) {
if (adventureData.currentDay != previousDay) {
VerifyZones(position);
}
}
public void Tick() { }
public void Dispose() {
// nothing here
}
}
}

View File

@@ -3,40 +3,23 @@ using System;
namespace Nox.Game {
[Serializable]
public class CombatKind : IEncounterKind {
public string enemyGroupId;
public string rewardTableId;
}
public class CombatKind : IEncounterKind { }
[Serializable]
public class SocialKind : IEncounterKind {
public string npcId;
public string factionId;
public int reputationDelta;
}
public class SocialKind : IEncounterKind { }
[Serializable]
public class PuzzleKind : IEncounterKind {
public string puzzleId;
public int difficultyClass;
}
public class PuzzleKind : IEncounterKind { }
[Serializable]
public class ExplorationKind : IEncounterKind {
public int perceptionDC;
}
public class ExplorationKind : IEncounterKind { }
[Serializable]
public class TutorialKind : IEncounterKind {
public string tutorialId;
}
public class TutorialKind : IEncounterKind { }
[Serializable]
public class HazardKind : IEncounterKind {
public int damageAmount;
}
public class HazardKind : IEncounterKind { }
[Serializable]
public class OtherKind : IEncounterKind {
}
public class OtherKind : IEncounterKind { }
}

View File

@@ -0,0 +1,18 @@
using Jovian.EncounterSystem;
using System;
using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "EncounterPrefabs", menuName = "Nox/EncounterPrefabs")]
public class EncounterPrefabs : ScriptableObject {
public EncounterSet[] encounterSets;
public AnswerPrefab answerPrefab;
}
[Serializable]
public class EncounterSet {
[field: SerializeReference, SubclassSelector]
public IEncounterKind encounterKind;
public EncounterReference encounterReference;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7fc36c84acd04836b1280aba57a64e24
timeCreated: 1777229589

View File

@@ -1,19 +1,43 @@
using Jovian.EncounterSystem;
using Nox.Game.UI;
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 void Initialize() {
throw new System.NotImplementedException();
private Dictionary<IEncounterKind, EncounterReference> encounterKindToPrefab = new ();
private IEncounterKind currentActiveKind;
public EncounterView(EncounterPrefabs encounterPrefabs) {
this.encounterPrefabs = encounterPrefabs;
}
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() {
throw new System.NotImplementedException();
currentActiveKind = currentEncounter.EncounterDefinition.Kind;
PopulateEncounterReference();
encounterKindToPrefab[currentActiveKind].gameObject.SetActive(true);
}
private void PopulateEncounterReference() {
}
public void Hide() {
throw new System.NotImplementedException();
}
public void Tick() {
throw new System.NotImplementedException();
encounterKindToPrefab[currentActiveKind].gameObject.SetActive(false);
}
public void Tick() { }
}
}

View File

@@ -1,4 +1,3 @@
using Jovian.ZoneSystem;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
@@ -9,12 +8,11 @@ namespace Nox.Game {
private readonly ICameraController cameraController;
private readonly InputSystem_Actions inputActions;
private readonly MapLocationsReference mapLocationsReference;
private readonly ZoneSystem zoneSystem;
private readonly EncounterHandler encounterHandler;
private readonly AdventureSettings adventureSettings;
private readonly float maxDistance = 100f;
private readonly AdventureData adventureData;
private AdventureData adventureData;
private bool partyCanMove;
private Vector3 targetPosition;
private bool shouldHover;
@@ -31,16 +29,15 @@ namespace Nox.Game {
ICameraController cameraController,
MapLocationsReference mapLocationsReference,
Input.InputSettings inputSettings,
ZoneSystem zoneSystem,
EncounterHandler encounterHandler,
AdventureData adventureData,
AdventureSettings adventureSettings) {
this.partyReference = partyReference;
this.cameraController = cameraController;
this.mapLocationsReference = mapLocationsReference;
this.zoneSystem = zoneSystem;
this.encounterHandler = encounterHandler;
this.adventureData = adventureData;
this.adventureSettings = adventureSettings;
inputActions = inputSettings.inputActions;
}
@@ -77,10 +74,14 @@ namespace Nox.Game {
if(!clickHit.collider.gameObject.transform.parent.TryGetComponent(out MapReference mapReference)) {
return;
}
//if(mapReference.ValidateMoveLocation(hitInfoPoint)) {
targetPosition = clickHit.point;
partyCanMove = true;
//}
if(ValidateMoveLocation(clickHit)) {
targetPosition = clickHit.point;
partyCanMove = true;
}
}
private bool ValidateMoveLocation(object hitInfoPoint) {
return true;
}
public void Tick() {
@@ -109,9 +110,13 @@ namespace Nox.Game {
VerifyPointsOfInterest();
partyCanMove = false;
}
adventureData.isPartyMoving = true;
partyReference.transform.position = Vector3.MoveTowards(new Vector3(partyReference.transform.position.x, 0, partyReference.transform.position.z), targetPosition, Time.deltaTime * adventureSettings.partyBaseSpeed);
VerifyZones(partyReference.transform.position);
partyReference.transform.position = Vector3.MoveTowards(
new Vector3(partyReference.transform.position.x, 0,
partyReference.transform.position.z), targetPosition,
Time.deltaTime * adventureSettings.partyBaseSpeed);
encounterHandler?.CheckForEncounters(partyReference.transform.position);
}
private void HandleHover() {
@@ -128,20 +133,6 @@ namespace Nox.Game {
currentSelectedPoi = null;
}
}
private void VerifyZones(Vector3 position) {
var zoneContext = zoneSystem.QueryZone(position);
var currentZoneId = zoneContext.resolvedZoneId;
if(currentZoneId != previousZoneId) {
if(!string.IsNullOrEmpty(currentZoneId)) {
Debug.Log($"Entered zone: {currentZoneId} (encounter: {zoneContext.encounterTableId}, safe: {zoneContext.isSafe})");
}
else if(!string.IsNullOrEmpty(previousZoneId)) {
Debug.Log($"Left zone: {previousZoneId}");
}
previousZoneId = currentZoneId;
}
}
private void VerifyPointsOfInterest() {
foreach(var location in mapLocationsReference.mapLocations) {
@@ -156,5 +147,4 @@ namespace Nox.Game {
inputActions.Player.ClickOnMap.performed -= OnClickOnMap;
}
}
}