First commit
This commit is contained in:
12
Assets/Code/GameState/PlayModes/AdventureModePrefabs.cs
Normal file
12
Assets/Code/GameState/PlayModes/AdventureModePrefabs.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Nox.Game.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
[CreateAssetMenu(fileName = "GameModePrefabs", menuName = "Nox/AdventureMapPrefabs")]
|
||||
public class AdventureModePrefabs: ScenePrefabs {
|
||||
public GuiReferences guiReferencesPrefab;
|
||||
public MapReference mapReferencePrefab;
|
||||
public MapLocationsReference mapLocationsReferencePrefab;
|
||||
public PartyReference partyReferencePrefab;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7cce6bb84bb20741a560389ab887769
|
||||
204
Assets/Code/GameState/PlayModes/AdventurePlayMode.cs
Normal file
204
Assets/Code/GameState/PlayModes/AdventurePlayMode.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using Jovian.Calendar;
|
||||
using Jovian.EncounterSystem;
|
||||
using Jovian.PopupSystem;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using Jovian.SaveSystem;
|
||||
using Jovian.ZoneSystem;
|
||||
using Nox.Core;
|
||||
using Nox.Platform;
|
||||
using Nox.Game.UI;
|
||||
using Nox.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using ZLinq;
|
||||
using PlayMode = Nox.Core.PlayMode;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class AdventureData {
|
||||
public bool isPartyMoving;
|
||||
public int currentDay = 0;
|
||||
public int suppliesAvailable = -1;
|
||||
public float currentTime = -1f;
|
||||
public DayPhase currentDayPhase = DayPhase.Morning;
|
||||
}
|
||||
|
||||
public class AdventurePlayMode : IPlayMode {
|
||||
private readonly PlatformSettings platformSettings;
|
||||
private readonly PlayModeSettings bootstrapSettings;
|
||||
private readonly GameDataState gameDataState;
|
||||
private readonly ISaveSystem saveSystem;
|
||||
private readonly PartyDefinition partyDefinition;
|
||||
private readonly AdventureSettings adventureSettings;
|
||||
private AdventureData adventureData;
|
||||
private AdventureModePrefabs scenePrefabs;
|
||||
private ICameraController cameraController;
|
||||
private MapReference mapRef;
|
||||
private PartyMovementHandler partyMovementHandler;
|
||||
private PartyReference partyRef;
|
||||
private MapLocationsReference mapLocationsReference;
|
||||
private InputSystem_Actions inputActions;
|
||||
private AdventureView adventureView;
|
||||
private ZoneSystem zoneSystem;
|
||||
private GuiReferences guiReferences;
|
||||
private TimeHandler timeHandler;
|
||||
private PartyInventoryHandler partyInventoryHandler;
|
||||
private PartyGuiView partyGuiView;
|
||||
private IPopupSystem popupSystem;
|
||||
private EncounterRegistry encounterRegistry;
|
||||
private EncounterHandler encounterHandler;
|
||||
private EncounterPrefabs encounterPrefabs;
|
||||
|
||||
public AdventurePlayMode(
|
||||
PlatformSettings platformSettings,
|
||||
PartyDefinition partyDefinition,
|
||||
PlayModeSettings bootstrapSettings,
|
||||
GameDataState gameDataState,
|
||||
ISaveSystem saveSystem,
|
||||
AdventureSettings adventureSettings,
|
||||
AdventureData adventureData) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.partyDefinition = partyDefinition;
|
||||
this.bootstrapSettings = bootstrapSettings;
|
||||
this.gameDataState = gameDataState;
|
||||
this.saveSystem = saveSystem;
|
||||
this.adventureSettings = adventureSettings;
|
||||
this.adventureData = adventureData;
|
||||
}
|
||||
|
||||
public bool IsGameModeInitialized { get; private set; }
|
||||
|
||||
public void EnterPlayMode() {
|
||||
inputActions = platformSettings.inputSettings.inputActions;
|
||||
if(IsGameModeInitialized) {
|
||||
inputActions.Player.Enable();
|
||||
inputActions.UI.PauseMenu.Enable();
|
||||
partyMovementHandler.ConsumeNextClick();
|
||||
return;
|
||||
}
|
||||
Addressables.LoadSceneAsync(bootstrapSettings.gameModeData.AsValueEnumerable().FirstOrDefault(g => g.playMode == PlayMode.Adventure)?.scene)
|
||||
.WaitForCompletion().ActivateAsync().completed += InitializeGameMode;
|
||||
}
|
||||
|
||||
private void InitializeGameMode(AsyncOperation obj) {
|
||||
inputActions.Player.Enable();
|
||||
inputActions.UI.PauseMenu.Enable();
|
||||
Debug.Log("Entering Adventure Play Mode");
|
||||
if(partyDefinition == null) {
|
||||
var restoreResult = NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData);
|
||||
if(restoreResult == null) {
|
||||
Debug.LogError("AdventurePlayMode: no save data found for auto-recovery. Party will be null.");
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
partyRef.transform.position = gameDataState.savedPartyPosition.Value;
|
||||
}
|
||||
mapLocationsReference ??= Object.FindFirstObjectByType<MapLocationsReference>();
|
||||
if(!mapRef) {
|
||||
mapRef ??= Object.Instantiate(scenePrefabs.mapReferencePrefab);
|
||||
}
|
||||
cameraController ??= new CameraController(platformSettings, mapRef);
|
||||
cameraController.Initialize();
|
||||
|
||||
if(adventureData.suppliesAvailable == -1) {
|
||||
adventureData.suppliesAvailable = adventureSettings.maxSupplies;
|
||||
}
|
||||
if(Mathf.Approximately(adventureData.currentTime, -1f)) {
|
||||
adventureData.currentTime = 0.25f;
|
||||
}
|
||||
|
||||
partyInventoryHandler ??= new PartyInventoryHandler(adventureData, adventureSettings);
|
||||
partyInventoryHandler.Initialize();
|
||||
|
||||
var calendarSettings = Addressables.LoadAssetAsync<CalendarSettings>("CalendarSettings").WaitForCompletion();
|
||||
var worldClock = new WorldClock(calendarSettings);
|
||||
timeHandler ??= new TimeHandler(adventureSettings, adventureData, worldClock);
|
||||
|
||||
zoneSystem ??= new ZoneSystem(mapRef.zonesObjectHolder);
|
||||
encounterHandler = new EncounterHandler(zoneSystem, encounterRegistry, encounterPrefabs);
|
||||
partyMovementHandler ??= new PartyMovementHandler(
|
||||
partyRef,
|
||||
cameraController,
|
||||
mapLocationsReference,
|
||||
platformSettings.inputSettings,
|
||||
encounterHandler,
|
||||
adventureData,
|
||||
adventureSettings);
|
||||
partyMovementHandler.Initialize();
|
||||
|
||||
guiReferences ??= Object.FindFirstObjectByType<GuiReferences>();
|
||||
adventureView ??= new AdventureView(gameDataState, guiReferences, inputActions, adventureData, adventureSettings, worldClock);
|
||||
adventureView.Initialize();
|
||||
|
||||
if(partyGuiView == null && guiReferences.partyMemberSlotPrefab != null) {
|
||||
var portraitsHolder = Addressables.LoadAssetAsync<PortraitsHolder>("PortraitsHolder").WaitForCompletion();
|
||||
|
||||
if(popupSystem == null) {
|
||||
var popupSettings = Addressables.LoadAssetAsync<PopupSettings>("PopupSettings").WaitForCompletion();
|
||||
var popupViewPrefab = Addressables.LoadAssetAsync<GameObject>("PopupReferencePrefab").WaitForCompletion().GetComponent<PopupReference>();
|
||||
var guiCanvas = guiReferences.GetComponentInParent<Canvas>().transform;
|
||||
popupSystem = new PopupSystem(popupSettings, popupViewPrefab, guiCanvas);
|
||||
popupSystem.RegisterCategory(PopupCategory.Character, priority: 10);
|
||||
}
|
||||
|
||||
partyGuiView = new PartyGuiView(guiReferences.portraitsContainer, guiReferences.partyMemberSlotPrefab, portraitsHolder, popupSystem);
|
||||
partyGuiView.Initialize(partyDefinition);
|
||||
}
|
||||
|
||||
IsGameModeInitialized = true;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if(!IsGameModeInitialized || gameDataState.ActiveParty == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
timeHandler.Tick();
|
||||
partyInventoryHandler.Tick();
|
||||
partyMovementHandler.Tick();
|
||||
encounterHandler.Tick();
|
||||
adventureView.Tick();
|
||||
partyGuiView?.Tick();
|
||||
popupSystem?.Tick(Time.deltaTime);
|
||||
|
||||
if(inputActions.UI.PauseMenu.WasPerformedThisFrame()) {
|
||||
gameDataState.ChangePlayMode(PlayMode.PauseMenu);
|
||||
}
|
||||
}
|
||||
public void LateTick() {
|
||||
if(!IsGameModeInitialized) {
|
||||
return;
|
||||
}
|
||||
cameraController.Tick();
|
||||
}
|
||||
public NoxSavedDataSet CaptureNoxSaveData() {
|
||||
return new NoxSavedDataSet {
|
||||
activePlayMode = PlayMode.Adventure,
|
||||
activeParty = partyDefinition,
|
||||
partyPosition = partyRef ? SerializableVector3.FromVector3(partyRef.transform.position) : SerializableVector3.Zero,
|
||||
adventureData = this.adventureData
|
||||
};
|
||||
}
|
||||
|
||||
public void ExitGameMode() {
|
||||
inputActions.Player.Disable();
|
||||
inputActions.UI.PauseMenu.Disable();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
partyGuiView?.Dispose();
|
||||
popupSystem?.Dispose();
|
||||
cameraController?.Dispose();
|
||||
partyMovementHandler?.Dispose();
|
||||
encounterHandler?.Dispose();
|
||||
encounterRegistry = null;
|
||||
Resources.UnloadUnusedAssets();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb1c247bb12a45a587e8ae7d013038d7
|
||||
timeCreated: 1771156737
|
||||
13
Assets/Code/GameState/PlayModes/AdventureSettings.cs
Normal file
13
Assets/Code/GameState/PlayModes/AdventureSettings.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
[CreateAssetMenu(fileName = "AdventureSettings", menuName = "Nox/AdventureSettings")]
|
||||
public class AdventureSettings : ScriptableObject {
|
||||
public int dayLength = 10;
|
||||
public int maxSupplies = 20;
|
||||
|
||||
[Header("Party Data")]
|
||||
public float partyBaseSpeed = 3f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d2424482c4843c0b7a33a9cc67411b2
|
||||
timeCreated: 1771786400
|
||||
31
Assets/Code/GameState/PlayModes/CombatPlayMode.cs
Normal file
31
Assets/Code/GameState/PlayModes/CombatPlayMode.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Nox.Core;
|
||||
using Nox.Platform;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class CombatPlayMode : IPlayMode {
|
||||
private readonly PlatformSettings platformSettings;
|
||||
private readonly PartyDefinition partyDefinition;
|
||||
|
||||
public CombatPlayMode(PlatformSettings platformSettings, PartyDefinition partyDefinition) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.partyDefinition = partyDefinition;
|
||||
}
|
||||
|
||||
public bool IsGameModeInitialized { get; private set; }
|
||||
|
||||
public void EnterPlayMode() {
|
||||
if(partyDefinition == null) {
|
||||
Debug.LogWarning("CombatPlayMode started without PartyData.");
|
||||
}
|
||||
|
||||
Debug.Log("Entering Combat Play Mode");
|
||||
IsGameModeInitialized = true;
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
public void LateTick() { }
|
||||
public void ExitGameMode() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
3
Assets/Code/GameState/PlayModes/CombatPlayMode.cs.meta
Normal file
3
Assets/Code/GameState/PlayModes/CombatPlayMode.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 087dc559ae894cd8b9a9dee5c6e3b64c
|
||||
timeCreated: 1772367690
|
||||
3
Assets/Code/GameState/PlayModes/Encounters.meta
Normal file
3
Assets/Code/GameState/PlayModes/Encounters.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6216fd41db9494aaa6c127d9d790b93
|
||||
timeCreated: 1776506857
|
||||
@@ -0,0 +1,11 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class AnswerReference : MonoBehaviour {
|
||||
public TextMeshProUGUI number;
|
||||
public TextMeshProUGUI dialogText;
|
||||
public Button button;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c14350aeeed44a28d98d22c6ef048dc
|
||||
timeCreated: 1777235448
|
||||
146
Assets/Code/GameState/PlayModes/Encounters/EncounterHandler.cs
Normal file
146
Assets/Code/GameState/PlayModes/Encounters/EncounterHandler.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 523274f9158f453dbfac02601a77c3f7
|
||||
timeCreated: 1776506833
|
||||
25
Assets/Code/GameState/PlayModes/Encounters/EncounterKind.cs
Normal file
25
Assets/Code/GameState/PlayModes/Encounters/EncounterKind.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Jovian.EncounterSystem;
|
||||
using System;
|
||||
|
||||
namespace Nox.Game {
|
||||
[Serializable]
|
||||
public class CombatKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class SocialKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class PuzzleKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class ExplorationKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class TutorialKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class HazardKind : IEncounterKind { }
|
||||
|
||||
[Serializable]
|
||||
public class OtherKind : IEncounterKind { }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abf01048c404a0240ad538b65a15f5fb
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class EncounterSet {
|
||||
[field: SerializeReference, SubclassSelector]
|
||||
public IEncounterKind encounterKind;
|
||||
public EncounterReference encounterReference;
|
||||
public AnswerReference answerReference;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc36c84acd04836b1280aba57a64e24
|
||||
timeCreated: 1777229589
|
||||
167
Assets/Code/GameState/PlayModes/Encounters/EncounterView.cs
Normal file
167
Assets/Code/GameState/PlayModes/Encounters/EncounterView.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
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 const int MaxAnswers = 4;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void SetCurrentEncounter(IEncounter encounter) {
|
||||
currentEncounter = encounter;
|
||||
}
|
||||
|
||||
public void Initialize() { }
|
||||
|
||||
public void Show() {
|
||||
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();
|
||||
currentReference.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Hide() {
|
||||
if(currentReference) {
|
||||
currentReference.gameObject.SetActive(false);
|
||||
}
|
||||
DeactivateAnswers(currentAnswerPool);
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b69490c9f1d8471a84b4594d1b1be117
|
||||
timeCreated: 1776590016
|
||||
30
Assets/Code/GameState/PlayModes/Encounters/RewardKind.cs
Normal file
30
Assets/Code/GameState/PlayModes/Encounters/RewardKind.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Jovian.EncounterSystem;
|
||||
using System;
|
||||
|
||||
namespace Nox.Game {
|
||||
[Serializable]
|
||||
public class CurrencyRewardKind : IRewardKind {
|
||||
public string currencyId;
|
||||
public int amount;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ItemRewardKind : IRewardKind {
|
||||
public string itemId;
|
||||
public int quantity;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ExperienceRewardKind : IRewardKind {
|
||||
public int amount;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UnlockableRewardKind : IRewardKind {
|
||||
public string unlockableId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class OtherRewardKind : IRewardKind {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7895041af87249e4c8458a07b0bc6b2c
|
||||
10
Assets/Code/GameState/PlayModes/IMenuView.cs
Normal file
10
Assets/Code/GameState/PlayModes/IMenuView.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Nox.Game.UI {
|
||||
public interface IMenuView {
|
||||
void Initialize();
|
||||
void Show();
|
||||
void Hide();
|
||||
void Tick();
|
||||
}
|
||||
}
|
||||
3
Assets/Code/GameState/PlayModes/IMenuView.cs.meta
Normal file
3
Assets/Code/GameState/PlayModes/IMenuView.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e99c535c23cc449984dcd145f4c1bec8
|
||||
timeCreated: 1772374016
|
||||
10
Assets/Code/GameState/PlayModes/MapLocation.cs
Normal file
10
Assets/Code/GameState/PlayModes/MapLocation.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class MapLocation : MonoBehaviour {
|
||||
public SpriteRenderer icon;
|
||||
public SpriteRenderer highlight;
|
||||
public TextMeshProUGUI nameText;
|
||||
}
|
||||
}
|
||||
2
Assets/Code/GameState/PlayModes/MapLocation.cs.meta
Normal file
2
Assets/Code/GameState/PlayModes/MapLocation.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 436b68ae9b9d347469b78e52a5aa7b53
|
||||
7
Assets/Code/GameState/PlayModes/MapLocationsReference.cs
Normal file
7
Assets/Code/GameState/PlayModes/MapLocationsReference.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class MapLocationsReference : MonoBehaviour {
|
||||
public NoxLocationInfo [] mapLocations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdd66cc132efc3640b46bf53dedcbcb4
|
||||
9
Assets/Code/GameState/PlayModes/MapReference.cs
Normal file
9
Assets/Code/GameState/PlayModes/MapReference.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Jovian.ZoneSystem;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class MapReference : MonoBehaviour {
|
||||
public GameObject mapPlane;
|
||||
public ZonesObjectHolder zonesObjectHolder;
|
||||
}
|
||||
}
|
||||
2
Assets/Code/GameState/PlayModes/MapReference.cs.meta
Normal file
2
Assets/Code/GameState/PlayModes/MapReference.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c173f913efc6004faf5dd75e96b32fe
|
||||
21
Assets/Code/GameState/PlayModes/NoxMapData.cs
Normal file
21
Assets/Code/GameState/PlayModes/NoxMapData.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public enum NoxMapLocations {
|
||||
None,
|
||||
City1,
|
||||
City2,
|
||||
Village1,
|
||||
Village2,
|
||||
Ruin1,
|
||||
Ruin2
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class NoxLocationInfo {
|
||||
public NoxMapLocations locationId;
|
||||
public MapLocation mapLocation;
|
||||
}
|
||||
|
||||
}
|
||||
3
Assets/Code/GameState/PlayModes/NoxMapData.cs.meta
Normal file
3
Assets/Code/GameState/PlayModes/NoxMapData.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 535e7fdf7ddb4c1f9edf7254c3bb0acd
|
||||
timeCreated: 1771763769
|
||||
25
Assets/Code/GameState/PlayModes/PartyInventoryHandler.cs
Normal file
25
Assets/Code/GameState/PlayModes/PartyInventoryHandler.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Nox.Game {
|
||||
public class PartyInventoryHandler {
|
||||
private readonly AdventureData adventureData;
|
||||
private readonly AdventureSettings adventureSettings;
|
||||
private int currentDay;
|
||||
|
||||
public PartyInventoryHandler(AdventureData adventureData, AdventureSettings adventureSettings) {
|
||||
this.adventureData = adventureData;
|
||||
this.adventureSettings = adventureSettings;
|
||||
}
|
||||
|
||||
public void Initialize() {
|
||||
currentDay = adventureData.currentDay;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if(currentDay != adventureData.currentDay) {
|
||||
currentDay = adventureData.currentDay;
|
||||
if(adventureData.suppliesAvailable > 0) {
|
||||
adventureData.suppliesAvailable--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4a1ab7b529042ca8bf42714b383f918
|
||||
timeCreated: 1773614576
|
||||
149
Assets/Code/GameState/PlayModes/PartyMovementHandler.cs
Normal file
149
Assets/Code/GameState/PlayModes/PartyMovementHandler.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class PartyMovementHandler {
|
||||
private readonly PartyReference partyReference;
|
||||
private readonly ICameraController cameraController;
|
||||
private readonly InputSystem_Actions inputActions;
|
||||
private readonly MapLocationsReference mapLocationsReference;
|
||||
private readonly EncounterHandler encounterHandler;
|
||||
private readonly AdventureSettings adventureSettings;
|
||||
private readonly float maxDistance = 100f;
|
||||
private readonly AdventureData adventureData;
|
||||
|
||||
private bool partyCanMove;
|
||||
private Vector3 targetPosition;
|
||||
private bool shouldHover;
|
||||
private MapLocation currentSelectedPoi;
|
||||
private bool hasClicked;
|
||||
private bool skipNextClick;
|
||||
|
||||
public LayerMask clickToMoveMask = LayerMask.GetMask("Clickable");
|
||||
public LayerMask hoverOverMask = LayerMask.GetMask("Hoverable");
|
||||
|
||||
public PartyMovementHandler(
|
||||
PartyReference partyReference,
|
||||
ICameraController cameraController,
|
||||
MapLocationsReference mapLocationsReference,
|
||||
Input.InputSettings inputSettings,
|
||||
EncounterHandler encounterHandler,
|
||||
AdventureData adventureData,
|
||||
AdventureSettings adventureSettings) {
|
||||
this.partyReference = partyReference;
|
||||
this.cameraController = cameraController;
|
||||
this.mapLocationsReference = mapLocationsReference;
|
||||
this.encounterHandler = encounterHandler;
|
||||
this.adventureData = adventureData;
|
||||
this.adventureSettings = adventureSettings;
|
||||
inputActions = inputSettings.inputActions;
|
||||
}
|
||||
|
||||
public void Initialize() {
|
||||
inputActions.Player.ClickOnMap.performed += OnClickOnMap;
|
||||
}
|
||||
|
||||
public void ConsumeNextClick() {
|
||||
skipNextClick = true;
|
||||
}
|
||||
|
||||
private void OnClickOnMap(InputAction.CallbackContext obj) {
|
||||
if(!obj.action.WasReleasedThisFrame()) {
|
||||
return;
|
||||
}
|
||||
hasClicked = true;
|
||||
}
|
||||
|
||||
private void HandleHoverableLocation(RaycastHit hitInfo) {
|
||||
var go = hitInfo.collider.gameObject;
|
||||
if(!go.transform.parent.TryGetComponent(out MapLocation mapLocation)) {
|
||||
return;
|
||||
}
|
||||
currentSelectedPoi = mapLocation;
|
||||
mapLocation.highlight.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void HandleClickableLocation() {
|
||||
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
|
||||
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
|
||||
if(!Physics.Raycast(ray, out var clickHit, maxDistance, clickToMoveMask, QueryTriggerInteraction.Ignore)) {
|
||||
return;
|
||||
}
|
||||
if(!clickHit.collider.gameObject.transform.parent.TryGetComponent(out MapReference mapReference)) {
|
||||
return;
|
||||
}
|
||||
if(ValidateMoveLocation(clickHit)) {
|
||||
targetPosition = clickHit.point;
|
||||
partyCanMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateMoveLocation(object hitInfoPoint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
HandleHover();
|
||||
|
||||
if(hasClicked) {
|
||||
hasClicked = false;
|
||||
// should it skip next click to avoid click-through from the pause menu?
|
||||
if(skipNextClick) {
|
||||
skipNextClick = false;
|
||||
return;
|
||||
}
|
||||
if(EventSystem.current.IsPointerOverGameObject()) {
|
||||
return;
|
||||
}
|
||||
HandleClickableLocation();
|
||||
}
|
||||
|
||||
if(!partyCanMove) {
|
||||
adventureData.isPartyMoving = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(Vector3.Distance(partyReference.transform.position, targetPosition) < 0.05f) {
|
||||
partyReference.transform.position = targetPosition;
|
||||
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);
|
||||
encounterHandler?.CheckForEncounters(partyReference.transform.position);
|
||||
}
|
||||
|
||||
private void HandleHover() {
|
||||
if(EventSystem.current.IsPointerOverGameObject()) {
|
||||
return;
|
||||
}
|
||||
var screenPos = inputActions.Player.Point.ReadValue<Vector2>();
|
||||
var ray = cameraController.CameraReference.mainCamera.ScreenPointToRay(screenPos);
|
||||
if(Physics.Raycast(ray, out var hoverHit, maxDistance, hoverOverMask, QueryTriggerInteraction.Ignore)) {
|
||||
HandleHoverableLocation(hoverHit);
|
||||
}
|
||||
else {
|
||||
currentSelectedPoi?.highlight.gameObject.SetActive(false);
|
||||
currentSelectedPoi = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyPointsOfInterest() {
|
||||
foreach(var location in mapLocationsReference.mapLocations) {
|
||||
if(Vector3.Distance(location.mapLocation.transform.position, partyReference.transform.position) < 0.4f) {
|
||||
Debug.Log($"Arrived at {location.locationId}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
inputActions.Player.ClickOnMap.performed -= OnClickOnMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2f697207298f2242aa2a8d36ef6a9b4
|
||||
47
Assets/Code/GameState/PlayModes/PauseMenuPlayMode.cs
Normal file
47
Assets/Code/GameState/PlayModes/PauseMenuPlayMode.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
#nullable enable
|
||||
using Nox.Core;
|
||||
using Nox.Platform;
|
||||
using Nox.Game.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class PauseMenuPlayMode : IPlayMode {
|
||||
private readonly PlatformSettings platformSettings;
|
||||
private readonly GameDataState gameDataState;
|
||||
private PauseMenuReferences? pauseMenuReference;
|
||||
private readonly IMenuView? pauseMenuView;
|
||||
private readonly InputSystem_Actions inputActions;
|
||||
|
||||
public PauseMenuPlayMode(PlatformSettings platformSettings, GameDataState gameDataState, IMenuView pauseMenuView) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.gameDataState = gameDataState;
|
||||
this.pauseMenuView = pauseMenuView;
|
||||
inputActions = platformSettings.inputSettings.inputActions;
|
||||
inputActions.UI.Enable();
|
||||
}
|
||||
|
||||
public bool IsGameModeInitialized { get; private set; }
|
||||
|
||||
public void EnterPlayMode() {
|
||||
Debug.Log("Entering PauseMenu Play Mode");
|
||||
pauseMenuView?.Initialize();
|
||||
IsGameModeInitialized = true;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if(inputActions.UI.PauseMenu.WasPerformedThisFrame()) {
|
||||
pauseMenuView?.Hide();
|
||||
gameDataState.ChangePlayMode(gameDataState.PreviousPlayMode);
|
||||
}
|
||||
pauseMenuView?.Tick();
|
||||
}
|
||||
public void LateTick() { }
|
||||
public void ExitGameMode() {
|
||||
pauseMenuView?.Hide();
|
||||
}
|
||||
public void Dispose() {
|
||||
inputActions.UI.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eab5b722cabf4ec7b79af55838d24ed4
|
||||
timeCreated: 1772367657
|
||||
31
Assets/Code/GameState/PlayModes/RestPlayMode.cs
Normal file
31
Assets/Code/GameState/PlayModes/RestPlayMode.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Nox.Core;
|
||||
using Nox.Platform;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class RestPlayMode : IPlayMode {
|
||||
private readonly PlatformSettings platformSettings;
|
||||
private readonly PartyDefinition partyDefinition;
|
||||
|
||||
public RestPlayMode(PlatformSettings platformSettings, PartyDefinition partyDefinition) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.partyDefinition = partyDefinition;
|
||||
}
|
||||
|
||||
public bool IsGameModeInitialized { get; private set; }
|
||||
|
||||
public void EnterPlayMode() {
|
||||
if(partyDefinition == null) {
|
||||
Debug.LogWarning("RestPlayMode started without PartyData.");
|
||||
}
|
||||
|
||||
Debug.Log("Entering Rest Play Mode");
|
||||
IsGameModeInitialized = true;
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
public void LateTick() { }
|
||||
public void ExitGameMode() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
3
Assets/Code/GameState/PlayModes/RestPlayMode.cs.meta
Normal file
3
Assets/Code/GameState/PlayModes/RestPlayMode.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67cb7d9e318d474694bc0addab3e8511
|
||||
timeCreated: 1772367678
|
||||
70
Assets/Code/GameState/PlayModes/TimeHandler.cs
Normal file
70
Assets/Code/GameState/PlayModes/TimeHandler.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Jovian.Calendar;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public enum DayPhase {
|
||||
Midnight,
|
||||
Dawn,
|
||||
Morning,
|
||||
Afternoon,
|
||||
Dusk,
|
||||
Night
|
||||
}
|
||||
|
||||
public class TimeHandler {
|
||||
private readonly AdventureSettings adventureSettings;
|
||||
private readonly AdventureData adventureData;
|
||||
private readonly WorldClock worldClock;
|
||||
|
||||
private float localTime;
|
||||
|
||||
private static readonly (float start, DayPhase phase)[] PhaseThresholds = {
|
||||
(0.00f, DayPhase.Midnight),
|
||||
(0.05f, DayPhase.Night),
|
||||
(0.17f, DayPhase.Dawn),
|
||||
(0.25f, DayPhase.Morning),
|
||||
(0.50f, DayPhase.Afternoon),
|
||||
(0.75f, DayPhase.Dusk),
|
||||
(0.90f, DayPhase.Night)
|
||||
};
|
||||
|
||||
public TimeHandler(AdventureSettings adventureSettings, AdventureData adventureData, WorldClock worldClock) {
|
||||
this.adventureSettings = adventureSettings;
|
||||
this.adventureData = adventureData;
|
||||
this.worldClock = worldClock;
|
||||
localTime = adventureData.currentTime * adventureSettings.dayLength;
|
||||
}
|
||||
|
||||
public void Tick() {
|
||||
if(!adventureData.isPartyMoving) {
|
||||
return;
|
||||
}
|
||||
|
||||
localTime += Time.deltaTime;
|
||||
|
||||
if(localTime >= adventureSettings.dayLength) {
|
||||
localTime -= adventureSettings.dayLength;
|
||||
}
|
||||
|
||||
var normalized = localTime / adventureSettings.dayLength;
|
||||
|
||||
worldClock.Tick(normalized);
|
||||
|
||||
adventureData.currentTime = normalized;
|
||||
adventureData.currentDayPhase = GetPhase(normalized);
|
||||
}
|
||||
|
||||
private static DayPhase GetPhase(float t) {
|
||||
var phase = DayPhase.Midnight;
|
||||
foreach(var (start, p) in PhaseThresholds) {
|
||||
if(t >= start) {
|
||||
phase = p;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return phase;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Code/GameState/PlayModes/TimeHandler.cs.meta
Normal file
2
Assets/Code/GameState/PlayModes/TimeHandler.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 071a61f838db8e640b460ce029a8d5a5
|
||||
31
Assets/Code/GameState/PlayModes/TownPlayMode.cs
Normal file
31
Assets/Code/GameState/PlayModes/TownPlayMode.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Nox.Core;
|
||||
using Nox.Platform;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Nox.Game {
|
||||
public class TownPlayMode : IPlayMode {
|
||||
private readonly PlatformSettings platformSettings;
|
||||
private readonly PartyDefinition partyDefinition;
|
||||
|
||||
public TownPlayMode(PlatformSettings platformSettings, PartyDefinition partyDefinition) {
|
||||
this.platformSettings = platformSettings;
|
||||
this.partyDefinition = partyDefinition;
|
||||
}
|
||||
|
||||
public bool IsGameModeInitialized { get; private set; }
|
||||
|
||||
public void EnterPlayMode() {
|
||||
if(partyDefinition == null) {
|
||||
Debug.LogWarning("TownPlayMode started without PartyData.");
|
||||
}
|
||||
|
||||
Debug.Log("Entering Town Play Mode");
|
||||
IsGameModeInitialized = true;
|
||||
}
|
||||
|
||||
public void Tick() { }
|
||||
public void LateTick() { }
|
||||
public void ExitGameMode() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
3
Assets/Code/GameState/PlayModes/TownPlayMode.cs.meta
Normal file
3
Assets/Code/GameState/PlayModes/TownPlayMode.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd57598925a54bad93fe730e15023d94
|
||||
timeCreated: 1772367666
|
||||
Reference in New Issue
Block a user