using Jovian.Calendar; 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 ZLinq; using UnityEngine; using UnityEngine.AddressableAssets; 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 PartyDefinition partyDefinition; 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 AdventureSettings adventureSettings; private TimeHandler timeHandler; private PartyInventoryHandler partyInventoryHandler; private PartyGuiView partyGuiView; private IPopupSystem popupSystem; 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 sessions = saveSystem.GetAllSessions().AsValueEnumerable().OrderByDescending(s => s.lastSaveDateUtc).ToList(); if(sessions.Count == 0) { return; } var latestSession = sessions[0]; var slots = saveSystem.GetSlots(latestSession.sessionId).AsValueEnumerable().OrderByDescending(s => s.timestampUtc).ToList(); if(slots.Count == 0) { return; } var latestSlot = slots[0]; var saveData = saveSystem.Load(latestSlot); Debug.Log($"Loaded save {latestSlot.DisplayLabel}"); if(saveData == null) { Debug.LogError("Failed to load save data"); return; } NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData); Debug.LogWarning("AdventurePlayMode started from the Adventure Scene. Loading the last Autosave"); } scenePrefabs ??= Addressables.LoadAssetAsync("AdventureMapPrefabs").WaitForCompletion(); mapRef ??= Object.FindFirstObjectByType(); partyRef ??= Object.FindFirstObjectByType(); if(partyRef && gameDataState.savedPartyPosition.HasValue) { partyRef.transform.position = gameDataState.savedPartyPosition.Value; } mapLocationsReference ??= Object.FindFirstObjectByType(); 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").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); partyMovementHandler.Initialize(); guiReferences ??= Object.FindFirstObjectByType(); adventureView ??= new AdventureView(gameDataState, guiReferences, inputActions, adventureData, adventureSettings, worldClock); adventureView.Initialize(); if(partyGuiView == null && guiReferences.partyMemberSlotPrefab != null) { var portraitsHolder = Addressables.LoadAssetAsync("PortraitsHolder").WaitForCompletion(); if(popupSystem == null) { var popupSettings = Addressables.LoadAssetAsync("PopupSettings").WaitForCompletion(); var popupViewPrefab = Addressables.LoadAssetAsync("PopupReferencePrefab").WaitForCompletion().GetComponent(); var guiCanvas = guiReferences.GetComponentInParent().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) { return; } timeHandler.Tick(); partyInventoryHandler.Tick(); partyMovementHandler.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 }; } public void ExitGameMode() { inputActions.Player.Disable(); inputActions.UI.PauseMenu.Disable(); } public void Dispose() { cameraController?.Dispose(); partyMovementHandler?.Dispose(); partyGuiView?.Dispose(); popupSystem?.Dispose(); } } }