mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Conditional Checks (#1052)
## Major features - Added `conditionalChecks` to star system configs. These allow you to automatically set or unset dialogue conditions, persistent conditions, and ship log facts based on other conditions being met, to handle more complex interactive situations that a single `requiredCondition` or `requiredFact` can't cover. Implements #1048 ## Bug fixes - Fixed custom items breaking if `pickupAudio` and `dropAudio` were not set. Custom items will now default to the warp core item sounds. Each sound can be disabled individually by specifying "None" as the audio type. - Fixed custom items breaking if `removeComponents` was set on the detail.
This commit is contained in:
commit
101a6b1e9c
@ -209,24 +209,6 @@ namespace NewHorizons.Builder.Props
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detail.item != null)
|
|
||||||
{
|
|
||||||
ItemBuilder.MakeItem(prop, go, sector, detail.item, mod);
|
|
||||||
isItem = true;
|
|
||||||
if (detail.hasPhysics)
|
|
||||||
{
|
|
||||||
NHLogger.LogWarning($"An item with the path {detail.path} has both '{nameof(DetailInfo.hasPhysics)}' and '{nameof(DetailInfo.item)}' set. This will usually result in undesirable behavior.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (detail.itemSocket != null)
|
|
||||||
{
|
|
||||||
ItemBuilder.MakeSocket(prop, go, sector, detail.itemSocket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Items should always be kept loaded else they will vanish in your hand as you leave the sector
|
|
||||||
if (isItem) detail.keepLoaded = true;
|
|
||||||
|
|
||||||
prop.transform.localScale = detail.stretch ?? (detail.scale != 0 ? Vector3.one * detail.scale : prefab.transform.localScale);
|
prop.transform.localScale = detail.stretch ?? (detail.scale != 0 ? Vector3.one * detail.scale : prefab.transform.localScale);
|
||||||
|
|
||||||
if (detail.removeChildren != null)
|
if (detail.removeChildren != null)
|
||||||
@ -271,11 +253,29 @@ namespace NewHorizons.Builder.Props
|
|||||||
prop = newDetailGO;
|
prop = newDetailGO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (detail.item != null)
|
||||||
|
{
|
||||||
|
ItemBuilder.MakeItem(prop, go, sector, detail.item, mod);
|
||||||
|
isItem = true;
|
||||||
|
if (detail.hasPhysics)
|
||||||
|
{
|
||||||
|
NHLogger.LogWarning($"An item with the path {detail.path} has both '{nameof(DetailInfo.hasPhysics)}' and '{nameof(DetailInfo.item)}' set. This will usually result in undesirable behavior.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detail.itemSocket != null)
|
||||||
|
{
|
||||||
|
ItemBuilder.MakeSocket(prop, go, sector, detail.itemSocket);
|
||||||
|
}
|
||||||
|
|
||||||
if (isItem)
|
if (isItem)
|
||||||
{
|
{
|
||||||
// Else when you put them down you can't pick them back up
|
// Else when you put them down you can't pick them back up
|
||||||
var col = prop.GetComponent<OWCollider>();
|
var col = prop.GetComponent<OWCollider>();
|
||||||
if (col != null) col._physicsRemoved = false;
|
if (col != null) col._physicsRemoved = false;
|
||||||
|
|
||||||
|
// Items should always be kept loaded else they will vanish in your hand as you leave the sector
|
||||||
|
detail.keepLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!detail.keepLoaded) GroupsBuilder.Make(prop, sector);
|
if (!detail.keepLoaded) GroupsBuilder.Make(prop, sector);
|
||||||
|
|||||||
@ -59,10 +59,18 @@ namespace NewHorizons.Builder.Props
|
|||||||
{
|
{
|
||||||
item.PickupAudio = AudioTypeHandler.GetAudioType(info.pickupAudio, mod);
|
item.PickupAudio = AudioTypeHandler.GetAudioType(info.pickupAudio, mod);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.PickupAudio = AudioType.ToolItemWarpCorePickUp;
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(info.dropAudio))
|
if (!string.IsNullOrEmpty(info.dropAudio))
|
||||||
{
|
{
|
||||||
item.DropAudio = AudioTypeHandler.GetAudioType(info.dropAudio, mod);
|
item.DropAudio = AudioTypeHandler.GetAudioType(info.dropAudio, mod);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.DropAudio = AudioType.ToolItemWarpCoreDrop;
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(info.socketAudio))
|
if (!string.IsNullOrEmpty(info.socketAudio))
|
||||||
{
|
{
|
||||||
item.SocketAudio = AudioTypeHandler.GetAudioType(info.socketAudio, mod);
|
item.SocketAudio = AudioTypeHandler.GetAudioType(info.socketAudio, mod);
|
||||||
|
|||||||
99
NewHorizons/Components/Conditionals/ConditionalsManager.cs
Normal file
99
NewHorizons/Components/Conditionals/ConditionalsManager.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using NewHorizons.External.Modules.Conditionals;
|
||||||
|
using NewHorizons.Handlers;
|
||||||
|
using NewHorizons.Utility.OWML;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NewHorizons.Components.Conditionals
|
||||||
|
{
|
||||||
|
public class ConditionalsManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
public const int MAX_RECURSION = 120;
|
||||||
|
|
||||||
|
List<ConditionalCheckInfo> _checks = new();
|
||||||
|
bool _checksScheduled;
|
||||||
|
int _recursionCount = 0;
|
||||||
|
bool _avoidRecursionLogSpam = false;
|
||||||
|
|
||||||
|
public void AddCheck(ConditionalCheckInfo check)
|
||||||
|
{
|
||||||
|
_checks.Add(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveCheck(ConditionalCheckInfo check)
|
||||||
|
{
|
||||||
|
_checks.Remove(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Awake()
|
||||||
|
{
|
||||||
|
GlobalMessenger.AddListener("DialogueConditionsReset", ScheduleChecks);
|
||||||
|
GlobalMessenger<string, bool>.AddListener("DialogueConditionChanged", ScheduleChecks);
|
||||||
|
GlobalMessenger<string, bool>.AddListener("NHPersistentConditionChanged", ScheduleChecks);
|
||||||
|
GlobalMessenger.AddListener("ShipLogUpdated", ScheduleChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnDestroy()
|
||||||
|
{
|
||||||
|
GlobalMessenger.RemoveListener("DialogueConditionsReset", ScheduleChecks);
|
||||||
|
GlobalMessenger<string, bool>.RemoveListener("DialogueConditionChanged", ScheduleChecks);
|
||||||
|
GlobalMessenger<string, bool>.RemoveListener("NHPersistentConditionChanged", ScheduleChecks);
|
||||||
|
GlobalMessenger.RemoveListener("ShipLogUpdated", ScheduleChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void LateUpdate()
|
||||||
|
{
|
||||||
|
if (_checksScheduled)
|
||||||
|
{
|
||||||
|
_checksScheduled = false;
|
||||||
|
DoChecks();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We had a frame without any checks being scheduled, so reset the recursion count and disable Update() again
|
||||||
|
_recursionCount = 0;
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoChecks()
|
||||||
|
{
|
||||||
|
if (_recursionCount >= MAX_RECURSION)
|
||||||
|
{
|
||||||
|
if (!_avoidRecursionLogSpam)
|
||||||
|
{
|
||||||
|
NHLogger.LogError($"Possible infinite loop detected while processing conditional checks; conditions were changed every single frame for {MAX_RECURSION} frames. This is likely caused by a mod using conflicting conditional checks that both set and unset the same condition.");
|
||||||
|
_avoidRecursionLogSpam = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var check in _checks)
|
||||||
|
{
|
||||||
|
bool checkPassed = ConditionalsHandler.Check(check.check);
|
||||||
|
ConditionalsHandler.ApplyEffects(check.then, checkPassed);
|
||||||
|
}
|
||||||
|
_recursionCount++;
|
||||||
|
// Allow Update() to run
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We schedule checks for the end of the frame instead of doing them immediately because GlobalMessenger doesn't support recursion and will throw an error if we update a condition that fires off another GlobalMessenger event
|
||||||
|
void ScheduleChecks()
|
||||||
|
{
|
||||||
|
_checksScheduled = true;
|
||||||
|
// Allow Update() to run
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could theoretically filter checks by conditionName here and only do the checks that matter, but the performance gain is likely not significant enough to be worth the extra complexity
|
||||||
|
void ScheduleChecks(string conditionName, bool conditionState)
|
||||||
|
{
|
||||||
|
ScheduleChecks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,6 +20,8 @@ namespace NewHorizons.Components.Props
|
|||||||
public bool ClearPickupConditionOnDrop;
|
public bool ClearPickupConditionOnDrop;
|
||||||
public string PickupFact;
|
public string PickupFact;
|
||||||
|
|
||||||
|
string _translatedName;
|
||||||
|
|
||||||
public ItemType ItemType
|
public ItemType ItemType
|
||||||
{
|
{
|
||||||
get => _type;
|
get => _type;
|
||||||
@ -28,7 +30,11 @@ namespace NewHorizons.Components.Props
|
|||||||
|
|
||||||
public override string GetDisplayName()
|
public override string GetDisplayName()
|
||||||
{
|
{
|
||||||
return TranslationHandler.GetTranslation(DisplayName, TranslationHandler.TextType.UI);
|
if (_translatedName == null)
|
||||||
|
{
|
||||||
|
_translatedName = TranslationHandler.GetTranslation(DisplayName, TranslationHandler.TextType.UI);
|
||||||
|
}
|
||||||
|
return _translatedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CheckIsDroppable()
|
public override bool CheckIsDroppable()
|
||||||
@ -90,6 +96,7 @@ namespace NewHorizons.Components.Props
|
|||||||
|
|
||||||
void PlayCustomSound(AudioType audioType)
|
void PlayCustomSound(AudioType audioType)
|
||||||
{
|
{
|
||||||
|
if (audioType == AudioType.None) return;
|
||||||
if (ItemBuilder.IsCustomItemType(ItemType))
|
if (ItemBuilder.IsCustomItemType(ItemType))
|
||||||
{
|
{
|
||||||
Locator.GetPlayerAudioController()._oneShotExternalSource.PlayOneShot(audioType);
|
Locator.GetPlayerAudioController()._oneShotExternalSource.PlayOneShot(audioType);
|
||||||
|
|||||||
15
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
15
NewHorizons/External/Configs/StarSystemConfig.cs
vendored
@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using NewHorizons.External.Modules;
|
using NewHorizons.External.Modules;
|
||||||
|
using NewHorizons.External.Modules.Conditionals;
|
||||||
using NewHorizons.External.SerializableData;
|
using NewHorizons.External.SerializableData;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using static NewHorizons.External.Modules.ShipLogModule;
|
using static NewHorizons.External.Modules.ShipLogModule;
|
||||||
@ -155,6 +156,11 @@ namespace NewHorizons.External.Configs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public CuriosityColorInfo[] curiosities;
|
public CuriosityColorInfo[] curiosities;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of conditional checks to be performed while in this star system.
|
||||||
|
/// </summary>
|
||||||
|
public ConditionalCheckInfo[] conditionalChecks;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extra data that may be used by extension mods
|
/// Extra data that may be used by extension mods
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -383,6 +389,15 @@ namespace NewHorizons.External.Configs
|
|||||||
GlobalMusic ??= otherConfig.GlobalMusic;
|
GlobalMusic ??= otherConfig.GlobalMusic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conditionalChecks != null && otherConfig.conditionalChecks != null)
|
||||||
|
{
|
||||||
|
conditionalChecks = Concatenate(conditionalChecks, otherConfig.conditionalChecks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
conditionalChecks ??= otherConfig.conditionalChecks;
|
||||||
|
}
|
||||||
|
|
||||||
entryPositions = Concatenate(entryPositions, otherConfig.entryPositions);
|
entryPositions = Concatenate(entryPositions, otherConfig.entryPositions);
|
||||||
curiosities = Concatenate(curiosities, otherConfig.curiosities);
|
curiosities = Concatenate(curiosities, otherConfig.curiosities);
|
||||||
initialReveal = Concatenate(initialReveal, otherConfig.initialReveal);
|
initialReveal = Concatenate(initialReveal, otherConfig.initialReveal);
|
||||||
|
|||||||
86
NewHorizons/External/Modules/Conditionals/ConditionalCheckInfo.cs
vendored
Normal file
86
NewHorizons/External/Modules/Conditionals/ConditionalCheckInfo.cs
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NewHorizons.External.Modules.Conditionals
|
||||||
|
{
|
||||||
|
[JsonObject]
|
||||||
|
public class ConditionalCheckInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The conditions that must be met for the check to pass
|
||||||
|
/// </summary>
|
||||||
|
public ConditionalCheckConditionsInfo check;
|
||||||
|
/// <summary>
|
||||||
|
/// The effects of the check if it passes
|
||||||
|
/// </summary>
|
||||||
|
public ConditionalCheckEffectsInfo then;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonObject]
|
||||||
|
public class ConditionalCheckConditionsInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if all of these dialogue conditions are set
|
||||||
|
/// </summary>
|
||||||
|
public string[] allConditionsSet;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if any of these dialogue conditions are set
|
||||||
|
/// </summary>
|
||||||
|
public string[] anyConditionsSet;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if all of these persistent conditions are set
|
||||||
|
/// </summary>
|
||||||
|
public string[] allPersistentConditionsSet;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if any of these persistent conditions are set
|
||||||
|
/// </summary>
|
||||||
|
public string[] anyPersistentConditionsSet;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if all of these ship log facts are revealed
|
||||||
|
/// </summary>
|
||||||
|
public string[] allFactsRevealed;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will only pass if any of these ship log facts are revealed
|
||||||
|
/// </summary>
|
||||||
|
public string[] anyFactsRevealed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the check should pass only if the conditions are not met
|
||||||
|
/// </summary>
|
||||||
|
public bool invert;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonObject]
|
||||||
|
public class ConditionalCheckEffectsInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The check will set these dialogue conditions if it passes
|
||||||
|
/// </summary>
|
||||||
|
public string[] setConditions;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will unset these dialogue conditions if it passes
|
||||||
|
/// </summary>
|
||||||
|
public string[] unsetConditions;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will set these persistent conditions if it passes
|
||||||
|
/// </summary>
|
||||||
|
public string[] setPersistentConditions;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will unset these persistent conditions if it passes
|
||||||
|
/// </summary>
|
||||||
|
public string[] unsetPersistentConditions;
|
||||||
|
/// <summary>
|
||||||
|
/// The check will reveal these ship log facts if it passes
|
||||||
|
/// </summary>
|
||||||
|
public string[] revealFacts;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the check should undo its effects if the conditions are not met anymore (unset the set conditions, etc.). Note: ship log facts cannot currently be unrevealed.
|
||||||
|
/// </summary>
|
||||||
|
public bool reversible;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -62,21 +62,25 @@ namespace NewHorizons.External.Modules.Props.Item
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.
|
/// The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.
|
||||||
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||||
|
/// Defaults to "ToolItemWarpCorePickUp". Set to "None" to disable the sound entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string pickupAudio;
|
public string pickupAudio;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The audio to play when this item is dropped. Only applies to custom/non-vanilla item types.
|
/// The audio to play when this item is dropped. Only applies to custom/non-vanilla item types.
|
||||||
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||||
|
/// Defaults to "ToolItemWarpCoreDrop". Set to "None" to disable the sound entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string dropAudio;
|
public string dropAudio;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The audio to play when this item is inserted into a socket. Only applies to custom/non-vanilla item types.
|
/// The audio to play when this item is inserted into a socket. Only applies to custom/non-vanilla item types.
|
||||||
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||||
|
/// Defaults to the pickup audio. Set to "None" to disable the sound entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string socketAudio;
|
public string socketAudio;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The audio to play when this item is removed from a socket. Only applies to custom/non-vanilla item types.
|
/// The audio to play when this item is removed from a socket. Only applies to custom/non-vanilla item types.
|
||||||
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
/// Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
|
||||||
|
/// Defaults to the drop audio. Set to "None" to disable the sound entirely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string unsocketAudio;
|
public string unsocketAudio;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
103
NewHorizons/Handlers/ConditionalsHandler.cs
Normal file
103
NewHorizons/Handlers/ConditionalsHandler.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using NewHorizons.External.Modules.Conditionals;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NewHorizons.Handlers
|
||||||
|
{
|
||||||
|
public static class ConditionalsHandler
|
||||||
|
{
|
||||||
|
public static bool Check(ConditionalCheckConditionsInfo check)
|
||||||
|
{
|
||||||
|
var dcm = DialogueConditionManager.SharedInstance;
|
||||||
|
|
||||||
|
var passed = true;
|
||||||
|
if (check.allConditionsSet != null && check.allConditionsSet.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.allConditionsSet.All(dcm.GetConditionState);
|
||||||
|
}
|
||||||
|
if (check.anyConditionsSet != null && check.anyConditionsSet.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.anyConditionsSet.Any(dcm.GetConditionState);
|
||||||
|
}
|
||||||
|
if (check.allPersistentConditionsSet != null && check.allPersistentConditionsSet.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.allPersistentConditionsSet.All(PlayerData.GetPersistentCondition);
|
||||||
|
}
|
||||||
|
if (check.anyPersistentConditionsSet != null && check.anyPersistentConditionsSet.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.anyPersistentConditionsSet.Any(PlayerData.GetPersistentCondition);
|
||||||
|
}
|
||||||
|
if (check.allFactsRevealed != null && check.allFactsRevealed.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.allFactsRevealed.All(ShipLogHandler.KnowsFact);
|
||||||
|
}
|
||||||
|
if (check.anyFactsRevealed != null && check.anyFactsRevealed.Length > 0)
|
||||||
|
{
|
||||||
|
passed = passed && check.anyFactsRevealed.Any(ShipLogHandler.KnowsFact);
|
||||||
|
}
|
||||||
|
if (check.invert)
|
||||||
|
{
|
||||||
|
passed = !passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ApplyEffects(ConditionalCheckEffectsInfo effects, bool checkPassed)
|
||||||
|
{
|
||||||
|
if ((checkPassed || effects.reversible) && effects.setConditions != null)
|
||||||
|
{
|
||||||
|
foreach (var condition in effects.setConditions)
|
||||||
|
{
|
||||||
|
if (DialogueConditionManager.SharedInstance.GetConditionState(condition) != checkPassed)
|
||||||
|
{
|
||||||
|
DialogueConditionManager.SharedInstance.SetConditionState(condition, checkPassed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((!checkPassed || effects.reversible) && effects.unsetConditions != null)
|
||||||
|
{
|
||||||
|
foreach (var condition in effects.unsetConditions)
|
||||||
|
{
|
||||||
|
if (DialogueConditionManager.SharedInstance.GetConditionState(condition) != !checkPassed)
|
||||||
|
{
|
||||||
|
DialogueConditionManager.SharedInstance.SetConditionState(condition, !checkPassed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((checkPassed || effects.reversible) && effects.setPersistentConditions != null)
|
||||||
|
{
|
||||||
|
foreach (var condition in effects.setPersistentConditions)
|
||||||
|
{
|
||||||
|
if (!PlayerData.GetPersistentCondition(condition) != checkPassed)
|
||||||
|
{
|
||||||
|
PlayerData.SetPersistentCondition(condition, checkPassed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((!checkPassed || effects.reversible) && effects.unsetPersistentConditions != null)
|
||||||
|
{
|
||||||
|
foreach (var condition in effects.unsetPersistentConditions)
|
||||||
|
{
|
||||||
|
if (PlayerData.GetPersistentCondition(condition) != !checkPassed)
|
||||||
|
{
|
||||||
|
PlayerData.SetPersistentCondition(condition, !checkPassed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (checkPassed && effects.revealFacts != null)
|
||||||
|
{
|
||||||
|
foreach (var fact in effects.revealFacts)
|
||||||
|
{
|
||||||
|
if (!ShipLogHandler.KnowsFact(fact))
|
||||||
|
{
|
||||||
|
Locator.GetShipLogManager().RevealFact(fact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ using UnityEngine;
|
|||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
using NewHorizons.OtherMods;
|
using NewHorizons.OtherMods;
|
||||||
using NewHorizons.Components.EOTE;
|
using NewHorizons.Components.EOTE;
|
||||||
using Epic.OnlineServices.Presence;
|
using NewHorizons.Components.Conditionals;
|
||||||
|
|
||||||
namespace NewHorizons.Handlers
|
namespace NewHorizons.Handlers
|
||||||
{
|
{
|
||||||
@ -32,6 +32,15 @@ namespace NewHorizons.Handlers
|
|||||||
SkyboxBuilder.Make(system.Config.Skybox, system.Mod);
|
SkyboxBuilder.Make(system.Config.Skybox, system.Mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (system.Config.conditionalChecks != null)
|
||||||
|
{
|
||||||
|
var conditionalsManager = new GameObject("ConditionalsManager").AddComponent<ConditionalsManager>();
|
||||||
|
foreach (var check in system.Config.conditionalChecks)
|
||||||
|
{
|
||||||
|
conditionalsManager.AddCheck(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No time loop or travel audio at the eye
|
// No time loop or travel audio at the eye
|
||||||
if (Main.Instance.CurrentStarSystem == "EyeOfTheUniverse") return;
|
if (Main.Instance.CurrentStarSystem == "EyeOfTheUniverse") return;
|
||||||
|
|
||||||
|
|||||||
@ -143,5 +143,13 @@ namespace NewHorizons.Patches.PlayerPatches
|
|||||||
{
|
{
|
||||||
NewHorizonsData.Save();
|
NewHorizonsData.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(PlayerData.SetPersistentCondition))]
|
||||||
|
public static void PlayerData_SetPersistentCondition(string condition, bool state)
|
||||||
|
{
|
||||||
|
// Firing off a custom event for the Conditionals system to use. This could've been done with direct calls or a Unity event but it felt cleaner to mirror the vanilla "DialogueConditionChanged" event.
|
||||||
|
GlobalMessenger<string, bool>.FireEvent("NHPersistentConditionChanged", condition, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1152,19 +1152,19 @@
|
|||||||
},
|
},
|
||||||
"pickupAudio": {
|
"pickupAudio": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
|
"description": "The audio to play when this item is picked up. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.\nDefaults to \"ToolItemWarpCorePickUp\". Set to \"None\" to disable the sound entirely."
|
||||||
},
|
},
|
||||||
"dropAudio": {
|
"dropAudio": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The audio to play when this item is dropped. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
|
"description": "The audio to play when this item is dropped. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.\nDefaults to \"ToolItemWarpCoreDrop\". Set to \"None\" to disable the sound entirely."
|
||||||
},
|
},
|
||||||
"socketAudio": {
|
"socketAudio": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The audio to play when this item is inserted into a socket. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
|
"description": "The audio to play when this item is inserted into a socket. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.\nDefaults to the pickup audio. Set to \"None\" to disable the sound entirely."
|
||||||
},
|
},
|
||||||
"unsocketAudio": {
|
"unsocketAudio": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The audio to play when this item is removed from a socket. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list."
|
"description": "The audio to play when this item is removed from a socket. Only applies to custom/non-vanilla item types.\nCan be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.\nDefaults to the drop audio. Set to \"None\" to disable the sound entirely."
|
||||||
},
|
},
|
||||||
"pickupCondition": {
|
"pickupCondition": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -110,6 +110,13 @@
|
|||||||
"$ref": "#/definitions/CuriosityColorInfo"
|
"$ref": "#/definitions/CuriosityColorInfo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"conditionalChecks": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of conditional checks to be performed while in this star system.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ConditionalCheckInfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
"extras": {
|
"extras": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Extra data that may be used by extension mods",
|
"description": "Extra data that may be used by extension mods",
|
||||||
@ -451,6 +458,117 @@
|
|||||||
"minimum": 0.0
|
"minimum": 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ConditionalCheckInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"check": {
|
||||||
|
"description": "The conditions that must be met for the check to pass",
|
||||||
|
"$ref": "#/definitions/ConditionalCheckConditionsInfo"
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"description": "The effects of the check if it passes",
|
||||||
|
"$ref": "#/definitions/ConditionalCheckEffectsInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConditionalCheckConditionsInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"allConditionsSet": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if all of these dialogue conditions are set",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anyConditionsSet": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if any of these dialogue conditions are set",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allPersistentConditionsSet": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if all of these persistent conditions are set",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anyPersistentConditionsSet": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if any of these persistent conditions are set",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allFactsRevealed": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if all of these ship log facts are revealed",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"anyFactsRevealed": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will only pass if any of these ship log facts are revealed",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"invert": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "If the check should pass only if the conditions are not met"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConditionalCheckEffectsInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"setConditions": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will set these dialogue conditions if it passes",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unsetConditions": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will unset these dialogue conditions if it passes",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"setPersistentConditions": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will set these persistent conditions if it passes",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unsetPersistentConditions": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will unset these persistent conditions if it passes",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"revealFacts": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "The check will reveal these ship log facts if it passes",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reversible": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "If the check should undo its effects if the conditions are not met anymore (unset the set conditions, etc.). Note: ship log facts cannot currently be unrevealed."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"$docs": {
|
"$docs": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user