mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Repair Volumes (#1085)
## Minor features - Added `repairVolumes` which act like the repairable nodes on the "satellite" in the Zero-G cave. Resolves #1084 [Examples PR](https://github.com/Outer-Wilds-New-Horizons/nh-examples/pull/59) Also in this PR I've fixed two unrelated minor issues that were causing warnings to be flagged on every build.
This commit is contained in:
commit
ce2b247ebf
@ -459,11 +459,6 @@ namespace NewHorizons.Builder.ShipLog
|
||||
|
||||
private static MapModeObject ConstructPrimaryNode(List<NewHorizonsBody> bodies)
|
||||
{
|
||||
float DistanceFromPrimary(NewHorizonsBody body)
|
||||
{
|
||||
return Mathf.Max(body.Config.Orbit.semiMajorAxis, body.Config.Orbit.staticPosition?.Length() ?? 0f);
|
||||
}
|
||||
|
||||
foreach (NewHorizonsBody body in bodies.Where(b => b.Config.Base.centerOfSolarSystem))
|
||||
{
|
||||
bodies.Sort((b, o) => b.Config.Orbit.semiMajorAxis.CompareTo(o.Config.Orbit.semiMajorAxis));
|
||||
|
||||
52
NewHorizons/Builder/Volumes/RepairVolumeBuilder.cs
Normal file
52
NewHorizons/Builder/Volumes/RepairVolumeBuilder.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using NewHorizons.Builder.Props;
|
||||
using NewHorizons.Components.Volumes;
|
||||
using NewHorizons.External.Modules.Props;
|
||||
using NewHorizons.External.Modules.Volumes.VolumeInfos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NewHorizons.Builder.Volumes
|
||||
{
|
||||
public static class RepairVolumeBuilder
|
||||
{
|
||||
public static NHRepairReceiver Make(GameObject planetGO, Sector sector, RepairVolumeInfo info)
|
||||
{
|
||||
// Repair receivers aren't technically volumes (no OWTriggerVolume) so we don't use the VolumeBuilder
|
||||
|
||||
var go = GeneralPropBuilder.MakeNew("RepairVolume", planetGO, sector, info);
|
||||
|
||||
if (info.shape != null)
|
||||
{
|
||||
ShapeBuilder.AddCollider(go, info.shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
var shapeInfo = new ShapeInfo()
|
||||
{
|
||||
type = ShapeType.Sphere,
|
||||
useShape = false,
|
||||
hasCollision = true,
|
||||
radius = info.radius,
|
||||
};
|
||||
ShapeBuilder.AddCollider(go, shapeInfo);
|
||||
}
|
||||
|
||||
var repairReceiver = go.AddComponent<NHRepairReceiver>();
|
||||
repairReceiver.displayName = info.name ?? info.rename ?? go.name;
|
||||
repairReceiver.repairFraction = info.repairFraction;
|
||||
repairReceiver.repairTime = info.repairTime;
|
||||
repairReceiver.repairDistance = info.repairDistance;
|
||||
repairReceiver.damagedCondition = info.damagedCondition;
|
||||
repairReceiver.repairedCondition = info.repairedCondition;
|
||||
repairReceiver.revealFact = info.revealFact;
|
||||
|
||||
go.SetActive(true);
|
||||
|
||||
return repairReceiver;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,6 +222,13 @@ namespace NewHorizons.Builder.Volumes
|
||||
VolumeBuilder.MakeAndEnable<ReferenceFrameBlockerVolume>(go, sector, referenceFrameBlockerVolume);
|
||||
}
|
||||
}
|
||||
if (config.Volumes.repairVolumes != null)
|
||||
{
|
||||
foreach (var repairVolume in config.Volumes.repairVolumes)
|
||||
{
|
||||
RepairVolumeBuilder.Make(go, sector, repairVolume);
|
||||
}
|
||||
}
|
||||
if (config.Volumes.speedTrapVolumes != null)
|
||||
{
|
||||
foreach (var speedTrapVolume in config.Volumes.speedTrapVolumes)
|
||||
|
||||
103
NewHorizons/Components/Volumes/NHRepairReceiver.cs
Normal file
103
NewHorizons/Components/Volumes/NHRepairReceiver.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using NewHorizons.Handlers;
|
||||
using OWML.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace NewHorizons.Components.Volumes
|
||||
{
|
||||
// RepairReceiver isn't set up for proper subclassing but a subclass is necessary for the first-person manipulator to detect it.
|
||||
public class NHRepairReceiver : RepairReceiver
|
||||
{
|
||||
public static Type RepairReceiverType = EnumUtils.Create<Type>("NewHorizons");
|
||||
|
||||
public class RepairEvent : UnityEvent<NHRepairReceiver> { }
|
||||
|
||||
public RepairEvent OnRepaired = new();
|
||||
public RepairEvent OnDamaged = new();
|
||||
|
||||
public string displayName;
|
||||
public float repairTime;
|
||||
public string damagedCondition;
|
||||
public string repairedCondition;
|
||||
public string revealFact;
|
||||
|
||||
float _repairFraction = 0f;
|
||||
UITextType _uiTextType = UITextType.None;
|
||||
|
||||
public float repairFraction
|
||||
{
|
||||
get => _repairFraction;
|
||||
set
|
||||
{
|
||||
var prevValue = _repairFraction;
|
||||
_repairFraction = Mathf.Clamp01(value);
|
||||
if (prevValue < 1f && _repairFraction >= 1f)
|
||||
{
|
||||
Repair();
|
||||
}
|
||||
else if (prevValue >= 1f && _repairFraction < 1f)
|
||||
{
|
||||
Damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public new virtual bool IsRepairable() => IsDamaged();
|
||||
public new virtual bool IsDamaged() => _repairFraction < 1f;
|
||||
public new virtual float GetRepairFraction() => _repairFraction;
|
||||
|
||||
protected new void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_type = RepairReceiverType;
|
||||
if (IsDamaged()) Damage();
|
||||
else Repair();
|
||||
}
|
||||
|
||||
public new virtual void RepairTick()
|
||||
{
|
||||
if (!IsRepairable()) return;
|
||||
repairFraction += Time.deltaTime / repairTime;
|
||||
}
|
||||
|
||||
public new virtual UITextType GetRepairableName()
|
||||
{
|
||||
if (_uiTextType != UITextType.None) return _uiTextType;
|
||||
var value = TranslationHandler.GetTranslation(displayName, TranslationHandler.TextType.UI);
|
||||
_uiTextType = (UITextType)TranslationHandler.AddUI(value, false);
|
||||
return _uiTextType;
|
||||
}
|
||||
|
||||
void Damage()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(damagedCondition))
|
||||
{
|
||||
DialogueConditionManager.SharedInstance.SetConditionState(damagedCondition, true);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(repairedCondition))
|
||||
{
|
||||
DialogueConditionManager.SharedInstance.SetConditionState(repairedCondition, false);
|
||||
}
|
||||
OnDamaged.Invoke(this);
|
||||
}
|
||||
|
||||
void Repair()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(damagedCondition))
|
||||
{
|
||||
DialogueConditionManager.SharedInstance.SetConditionState(damagedCondition, false);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(repairedCondition))
|
||||
{
|
||||
DialogueConditionManager.SharedInstance.SetConditionState(repairedCondition, true);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(revealFact))
|
||||
{
|
||||
Locator.GetShipLogManager().RevealFact(revealFact);
|
||||
}
|
||||
OnRepaired.Invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
NewHorizons/External/Modules/Volumes/VolumeInfos/RepairVolumeInfo.cs
vendored
Normal file
49
NewHorizons/External/Modules/Volumes/VolumeInfos/RepairVolumeInfo.cs
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NewHorizons.External.Modules.Volumes.VolumeInfos
|
||||
{
|
||||
[JsonObject]
|
||||
public class RepairVolumeInfo : VolumeInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The name displayed in the UI when the player is repairing this object. If not set, the name of the object will be used.
|
||||
/// </summary>
|
||||
public string name;
|
||||
|
||||
/// <summary>
|
||||
/// How much of the object is initially repaired. 0 = not repaired, 1 = fully repaired.
|
||||
/// </summary>
|
||||
[DefaultValue(0f)] public float repairFraction = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// The time it takes to repair the object. Defaults to 3 seconds.
|
||||
/// </summary>
|
||||
[DefaultValue(3f)] public float repairTime = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// The distance from the object that the player can be to repair it. Defaults to 3 meters.
|
||||
/// </summary>
|
||||
[DefaultValue(3f)] public float repairDistance = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// A dialogue condition that will be set while the object is damaged. It will be unset when the object is repaired.
|
||||
/// </summary>
|
||||
public string damagedCondition;
|
||||
|
||||
/// <summary>
|
||||
/// A dialogue condition that will be set when the object is repaired. It will be unset if the object is damaged again.
|
||||
/// </summary>
|
||||
public string repairedCondition;
|
||||
|
||||
/// <summary>
|
||||
/// A ship log fact that will be revealed when the object is repaired.
|
||||
/// </summary>
|
||||
public string revealFact;
|
||||
}
|
||||
}
|
||||
@ -85,6 +85,11 @@ namespace NewHorizons.External.Modules.Volumes
|
||||
/// </summary>
|
||||
public VolumeInfo[] referenceFrameBlockerVolumes;
|
||||
|
||||
/// <summary>
|
||||
/// Add repair volumes to this planet.
|
||||
/// </summary>
|
||||
public RepairVolumeInfo[] repairVolumes;
|
||||
|
||||
/// <summary>
|
||||
/// Add triggers that reveal parts of the ship log on this planet.
|
||||
/// </summary>
|
||||
|
||||
62
NewHorizons/Patches/VolumePatches/RepairReceiverPatches.cs
Normal file
62
NewHorizons/Patches/VolumePatches/RepairReceiverPatches.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.Components.Volumes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NewHorizons.Patches.VolumePatches
|
||||
{
|
||||
|
||||
[HarmonyPatch(typeof(RepairReceiver))]
|
||||
public static class RepairReceiverPatches
|
||||
{
|
||||
// We can't actually override these methods so we patch the base class methods to invoke the subclass methods dynamically
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(RepairReceiver.IsRepairable))]
|
||||
public static void IsRepairable(RepairReceiver __instance, ref bool __result)
|
||||
{
|
||||
if (__instance is NHRepairReceiver r)
|
||||
{
|
||||
__result = r.IsRepairable();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(RepairReceiver.RepairTick))]
|
||||
public static void RepairTick(RepairReceiver __instance)
|
||||
{
|
||||
if (__instance is NHRepairReceiver r)
|
||||
{
|
||||
r.RepairTick();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(RepairReceiver.IsDamaged))]
|
||||
public static void IsDamaged(RepairReceiver __instance, ref bool __result)
|
||||
{
|
||||
if (__instance is NHRepairReceiver r)
|
||||
{
|
||||
__result = r.IsDamaged();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(RepairReceiver.GetRepairableName))]
|
||||
public static void GetRepairableName(RepairReceiver __instance, ref UITextType __result)
|
||||
{
|
||||
if (__instance is NHRepairReceiver r)
|
||||
{
|
||||
__result = r.GetRepairableName();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix, HarmonyPatch(nameof(RepairReceiver.GetRepairFraction))]
|
||||
public static void GetRepairFraction(RepairReceiver __instance, ref float __result)
|
||||
{
|
||||
if (__instance is NHRepairReceiver r)
|
||||
{
|
||||
__result = r.GetRepairFraction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5450,6 +5450,13 @@
|
||||
"$ref": "#/definitions/VolumeInfo"
|
||||
}
|
||||
},
|
||||
"repairVolumes": {
|
||||
"type": "array",
|
||||
"description": "Add repair volumes to this planet.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/RepairVolumeInfo"
|
||||
}
|
||||
},
|
||||
"revealVolumes": {
|
||||
"type": "array",
|
||||
"description": "Add triggers that reveal parts of the ship log on this planet.",
|
||||
@ -6722,6 +6729,83 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"RepairVolumeInfo": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"radius": {
|
||||
"type": "number",
|
||||
"description": "The radius of this volume, if a shape is not specified.",
|
||||
"format": "float",
|
||||
"default": 1.0
|
||||
},
|
||||
"shape": {
|
||||
"description": "The shape of this volume. Defaults to a sphere with a radius of `radius` if not specified.",
|
||||
"$ref": "#/definitions/ShapeInfo"
|
||||
},
|
||||
"rotation": {
|
||||
"description": "Rotation of the object",
|
||||
"$ref": "#/definitions/MVector3"
|
||||
},
|
||||
"alignRadial": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
],
|
||||
"description": "Do we try to automatically align this object to stand upright relative to the body's center? Stacks with rotation.\nDefaults to true for geysers, tornados, and volcanoes, and false for everything else."
|
||||
},
|
||||
"position": {
|
||||
"description": "Position of the object",
|
||||
"$ref": "#/definitions/MVector3"
|
||||
},
|
||||
"isRelativeToParent": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the positional and rotational coordinates are relative to parent instead of the root planet object."
|
||||
},
|
||||
"parentPath": {
|
||||
"type": "string",
|
||||
"description": "The relative path from the planet to the parent of this object. Optional (will default to the root sector)."
|
||||
},
|
||||
"rename": {
|
||||
"type": "string",
|
||||
"description": "An optional rename of this object"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name displayed in the UI when the player is repairing this object. If not set, the name of the object will be used."
|
||||
},
|
||||
"repairFraction": {
|
||||
"type": "number",
|
||||
"description": "How much of the object is initially repaired. 0 = not repaired, 1 = fully repaired.",
|
||||
"format": "float",
|
||||
"default": 0.0
|
||||
},
|
||||
"repairTime": {
|
||||
"type": "number",
|
||||
"description": "The time it takes to repair the object. Defaults to 3 seconds.",
|
||||
"format": "float",
|
||||
"default": 3.0
|
||||
},
|
||||
"repairDistance": {
|
||||
"type": "number",
|
||||
"description": "The distance from the object that the player can be to repair it. Defaults to 3 meters.",
|
||||
"format": "float",
|
||||
"default": 3.0
|
||||
},
|
||||
"damagedCondition": {
|
||||
"type": "string",
|
||||
"description": "A dialogue condition that will be set while the object is damaged. It will be unset when the object is repaired."
|
||||
},
|
||||
"repairedCondition": {
|
||||
"type": "string",
|
||||
"description": "A dialogue condition that will be set when the object is repaired. It will be unset if the object is damaged again."
|
||||
},
|
||||
"revealFact": {
|
||||
"type": "string",
|
||||
"description": "A ship log fact that will be revealed when the object is repaired."
|
||||
}
|
||||
}
|
||||
},
|
||||
"RevealVolumeInfo": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user