Merge branch 'master' into no-more-CR

This commit is contained in:
Nick 2022-05-02 02:59:20 -04:00
commit ba1636c214
24 changed files with 357 additions and 100 deletions

View File

@ -19,14 +19,18 @@ namespace NewHorizons.Builder.Orbital
var lineRenderer = orbitGO.AddComponent<LineRenderer>(); var lineRenderer = orbitGO.AddComponent<LineRenderer>();
lineRenderer.material = config.Orbit.DottedOrbitLine ? GameObject.Find("HearthianMapSatellite_Body/OrbitLine").GetComponent<LineRenderer>().material : GameObject.Find("OrbitLine_CO").GetComponent<LineRenderer>().material;
OrbitLine orbitLinePrefab; lineRenderer.textureMode = config.Orbit.DottedOrbitLine ? LineTextureMode.RepeatPerSegment : LineTextureMode.Stretch;
orbitLinePrefab = GameObject.Find("GiantsDeep_Body/OrbitLine_GD").GetComponent<OrbitLine>();
//orbitLinePrefab = GameObject.Find("HearthianMapSatellite_Body/OrbitLine").GetComponent<OrbitLine>(); var width = config.Orbit.DottedOrbitLine ? 100 : 50;
lineRenderer.material = orbitLinePrefab.GetComponent<LineRenderer>().material; lineRenderer.startWidth = width;
lineRenderer.endWidth = width;
lineRenderer.useWorldSpace = false; lineRenderer.useWorldSpace = false;
lineRenderer.loop = false; lineRenderer.loop = false;
var numVerts = config.Orbit.DottedOrbitLine ? 128 : 256;
lineRenderer.positionCount = numVerts;
var ecc = config.Orbit.Eccentricity; var ecc = config.Orbit.Eccentricity;
var parentGravity = astroObject.GetPrimaryBody()?.GetGravityVolume(); var parentGravity = astroObject.GetPrimaryBody()?.GetGravityVolume();
@ -65,9 +69,10 @@ namespace NewHorizons.Builder.Orbital
orbitLine._astroObject = astroObject; orbitLine._astroObject = astroObject;
orbitLine._fade = fade; orbitLine._fade = fade;
orbitLine._lineWidth = 0.2f; orbitLine._lineWidth = 0.2f;
orbitLine._numVerts = (int)Mathf.Clamp(config.Orbit.SemiMajorAxis / 1000f, 128, 4096); orbitLine._numVerts = (int)Mathf.Clamp(config.Orbit.SemiMajorAxis / 1000f, numVerts, 4096);
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(orbitLine.InitializeLineRenderer); Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(orbitLine.InitializeLineRenderer);
} }

View File

@ -85,9 +85,23 @@ namespace NewHorizons.Builder.Props
if (component is GhostIK) (component as GhostIK).enabled = false; if (component is GhostIK) (component as GhostIK).enabled = false;
if (component is GhostEffects) (component as GhostEffects).enabled = false; if (component is GhostEffects) (component as GhostEffects).enabled = false;
// If it's not a moving anglerfish make sure the anim controller is off // If it's not a moving anglerfish make sure the anim controller is regular
if(component is AnglerfishAnimController && component.GetComponentInParent<AnglerfishController>() == null) if(component is AnglerfishAnimController && component.GetComponentInParent<AnglerfishController>() == null)
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => (component as AnglerfishAnimController).enabled = false); Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady, () =>
{
Logger.Log("Enabling anglerfish animation");
var angler = (component as AnglerfishAnimController);
// Remove any reference to its angler
if(angler._anglerfishController)
{
angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState;
angler._anglerfishController.OnAnglerTurn -= angler.OnAnglerTurn;
angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended;
angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended;
}
angler.enabled = true;
angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking);
});
if (component is Animator) Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady, () => (component as Animator).enabled = true); if (component is Animator) Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady, () => (component as Animator).enabled = true);
if (component is Collider) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => (component as Collider).enabled = true); if (component is Collider) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => (component as Collider).enabled = true);
@ -134,6 +148,8 @@ namespace NewHorizons.Builder.Props
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.forward); if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.forward);
if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.up); if (front.sqrMagnitude == 0f) front = Vector3.Cross(up, Vector3.up);
front = rot * front;
prop.transform.LookAt(prop.transform.position + front, up); prop.transform.LookAt(prop.transform.position + front, up);
} }

View File

@ -16,10 +16,16 @@ namespace NewHorizons.Builder.Props
{ {
public static void Make(GameObject go, Sector sector, PropModule.DialogueInfo info, IModBehaviour mod) public static void Make(GameObject go, Sector sector, PropModule.DialogueInfo info, IModBehaviour mod)
{ {
// In stock I think they disable dialogue stuff with conditions
// Here we just don't make it at all
if (info.blockAfterPersistentCondition != null && PlayerData._currentGameSave.GetPersistentCondition(info.blockAfterPersistentCondition)) return; if (info.blockAfterPersistentCondition != null && PlayerData._currentGameSave.GetPersistentCondition(info.blockAfterPersistentCondition)) return;
var dialogue = MakeConversationZone(go, sector, info, mod.ModHelper); var dialogue = MakeConversationZone(go, sector, info, mod.ModHelper);
if (info.remoteTriggerPosition != null) MakeRemoteDialogueTrigger(go, sector, info, dialogue); if (info.remoteTriggerPosition != null) MakeRemoteDialogueTrigger(go, sector, info, dialogue);
// Make the character look at the player
// Useful for dialogue replacement
if (!string.IsNullOrEmpty(info.pathToAnimController)) MakePlayerTrackingZone(go, dialogue, info);
} }
public static void MakeRemoteDialogueTrigger(GameObject go, Sector sector, PropModule.DialogueInfo info, CharacterDialogueTree dialogue) public static void MakeRemoteDialogueTrigger(GameObject go, Sector sector, PropModule.DialogueInfo info, CharacterDialogueTree dialogue)
@ -81,6 +87,83 @@ namespace NewHorizons.Builder.Props
return dialogueTree; return dialogueTree;
} }
public static void MakePlayerTrackingZone(GameObject go, CharacterDialogueTree dialogue, PropModule.DialogueInfo info)
{
var character = go.transform.Find(info.pathToAnimController);
// At most one of these should ever not be null
var nomaiController = character.GetComponent<SolanumAnimController>();
var controller = character.GetComponent<CharacterAnimController>();
var lookOnlyWhenTalking = info.lookAtRadius <= 0;
// To have them look when you start talking
if (controller != null)
{
controller._dialogueTree = dialogue;
controller.lookOnlyWhenTalking = lookOnlyWhenTalking;
}
else if(nomaiController != null)
{
if (lookOnlyWhenTalking)
{
dialogue.OnStartConversation += nomaiController.StartWatchingPlayer;
dialogue.OnEndConversation += nomaiController.StopWatchingPlayer;
}
}
else
{
// TODO: make a custom controller for basic characters to just turn them to face you
}
if (info.lookAtRadius > 0)
{
GameObject playerTrackingZone = new GameObject("PlayerTrackingZone");
playerTrackingZone.SetActive(false);
playerTrackingZone.layer = LayerMask.NameToLayer("BasicEffectVolume");
playerTrackingZone.SetActive(false);
var sphereCollider = playerTrackingZone.AddComponent<SphereCollider>();
sphereCollider.radius = info.lookAtRadius;
sphereCollider.isTrigger = true;
playerTrackingZone.AddComponent<OWCollider>();
var triggerVolume = playerTrackingZone.AddComponent<OWTriggerVolume>();
if (controller)
{
// Since the Awake method is CharacterAnimController was already called
if (controller.playerTrackingZone)
{
controller.playerTrackingZone.OnEntry -= controller.OnZoneEntry;
controller.playerTrackingZone.OnExit -= controller.OnZoneExit;
}
// Set it to use the new zone
controller.playerTrackingZone = triggerVolume;
triggerVolume.OnEntry += controller.OnZoneEntry;
triggerVolume.OnExit += controller.OnZoneExit;
}
// Simpler for the Nomai
else if(nomaiController)
{
triggerVolume.OnEntry += (_) => nomaiController.StartWatchingPlayer();
triggerVolume.OnExit += (_) => nomaiController.StopWatchingPlayer();
}
// No controller
else
{
// TODO
}
playerTrackingZone.transform.parent = dialogue.gameObject.transform;
playerTrackingZone.transform.localPosition = Vector3.zero;
playerTrackingZone.SetActive(true);
}
}
private static void AddTranslation(string xml) private static void AddTranslation(string xml)
{ {
XmlDocument xmlDocument = new XmlDocument(); XmlDocument xmlDocument = new XmlDocument();

View File

@ -46,16 +46,17 @@ namespace NewHorizons.Builder.Props
{ {
foreach(var tornadoInfo in config.Props.Tornados) foreach(var tornadoInfo in config.Props.Tornados)
{ {
TornadoBuilder.Make(go, sector, tornadoInfo, config.Atmosphere?.Cloud != null); //TornadoBuilder.Make(go, sector, tornadoInfo, config.Atmosphere?.Cloud != null);
} }
} }
if (config.Props.Volcanos != null) if (config.Props.Volcanoes != null)
{ {
foreach (var volcanoInfo in config.Props.Volcanos) foreach (var volcanoInfo in config.Props.Volcanoes)
{ {
VolcanoBuilder.Make(go, sector, volcanoInfo); VolcanoBuilder.Make(go, sector, volcanoInfo);
} }
} }
// Reminder that dialogue has to be built after props if they're going to be using CharacterAnimController stuff
if (config.Props.Dialogue != null) if (config.Props.Dialogue != null)
{ {
foreach(var dialogueInfo in config.Props.Dialogue) foreach(var dialogueInfo in config.Props.Dialogue)

View File

@ -161,7 +161,7 @@ namespace NewHorizons.Builder.Props
{ {
try try
{ {
clip = AudioUtility.LoadAudio(mod.ModHelper.Manifest.ModFolderPath + "/" + info.AudioFilePath); clip = AudioUtilities.LoadAudio(mod.ModHelper.Manifest.ModFolderPath + "/" + info.AudioFilePath);
} }
catch(Exception e) catch(Exception e)
{ {
@ -198,7 +198,8 @@ namespace NewHorizons.Builder.Props
_customCurve = GameObject.Find("Moon_Body/Sector_THM/Characters_THM/Villager_HEA_Esker/Signal_Whistling").GetComponent<AudioSource>().GetCustomCurve(AudioSourceCurveType.CustomRolloff); _customCurve = GameObject.Find("Moon_Body/Sector_THM/Characters_THM/Villager_HEA_Esker/Signal_Whistling").GetComponent<AudioSource>().GetCustomCurve(AudioSourceCurveType.CustomRolloff);
source.SetCustomCurve(AudioSourceCurveType.CustomRolloff, _customCurve); source.SetCustomCurve(AudioSourceCurveType.CustomRolloff, _customCurve);
source.playOnAwake = false; // If it can be heard regularly then we play it immediately
source.playOnAwake = !info.OnlyAudibleToScope;
source.spatialBlend = 1f; source.spatialBlend = 1f;
source.volume = 0.5f; source.volume = 0.5f;
source.dopplerLevel = 0; source.dopplerLevel = 0;

View File

@ -17,6 +17,7 @@ namespace NewHorizons.Builder.Props
var launcherGO = prefab.InstantiateInactive(); var launcherGO = prefab.InstantiateInactive();
launcherGO.transform.parent = sector.transform; launcherGO.transform.parent = sector.transform;
launcherGO.transform.localPosition = info.position == null ? Vector3.zero : (Vector3) info.position; launcherGO.transform.localPosition = info.position == null ? Vector3.zero : (Vector3) info.position;
launcherGO.transform.rotation = Quaternion.FromToRotation(launcherGO.transform.TransformDirection(Vector3.up), ((Vector3)info.position).normalized).normalized;
launcherGO.name = "MeteorLauncher"; launcherGO.name = "MeteorLauncher";
var meteorLauncher = launcherGO.GetComponent<MeteorLauncher>(); var meteorLauncher = launcherGO.GetComponent<MeteorLauncher>();
@ -24,30 +25,49 @@ namespace NewHorizons.Builder.Props
meteorLauncher._detectableFluid = null; meteorLauncher._detectableFluid = null;
meteorLauncher._detectableField = null; meteorLauncher._detectableField = null;
meteorLauncher._launchDirection = info.position == null ? Vector3.up : ((Vector3)info.position).normalized; meteorLauncher._launchDirection = Vector3.up;
var meteorPrefab = GameObject.Instantiate(meteorLauncher._meteorPrefab); meteorLauncher._dynamicProbability = 0f;
FixMeteor(meteorPrefab, info);
meteorLauncher._meteorPrefab = meteorPrefab; meteorLauncher._minLaunchSpeed = info.minLaunchSpeed;
meteorLauncher._maxLaunchSpeed = info.maxLaunchSpeed;
meteorLauncher._minInterval = info.minInterval;
meteorLauncher._maxInterval = info.maxInterval;
launcherGO.SetActive(true); launcherGO.SetActive(true);
// Kill the prefab when its done with it // Have to null check else it breaks on reload configs
Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => meteorPrefab.SetActive(false)); Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady && meteorLauncher._meteorPool != null, () => {
foreach (var meteor in meteorLauncher._meteorPool)
{
FixMeteor(meteor, info);
}
});
} }
private static void FixMeteor(GameObject meteor, PropModule.VolcanoInfo info) private static void FixMeteor(MeteorController meteor, PropModule.VolcanoInfo info)
{ {
var mat = meteor.GetComponentInChildren<MeshRenderer>().material; var mat = meteor.GetComponentInChildren<MeshRenderer>().material;
mat.SetColor("_Color", info.stoneTint == null ? defaultStoneTint : info.stoneTint.ToColor()); mat.SetColor("_Color", info.stoneTint == null ? defaultStoneTint : info.stoneTint.ToColor());
mat.SetColor("_EmissionColor", info.lavaTint == null ? defaultLavaTint : info.lavaTint.ToColor()); mat.SetColor("_EmissionColor", info.lavaTint == null ? defaultLavaTint : info.lavaTint.ToColor());
var detectors = meteor.transform.Find("ConstantDetectors"); var detectors = meteor.transform.Find("ConstantDetectors").gameObject;
GameObject.Destroy(detectors.GetComponent<ConstantForceDetector>()); GameObject.Destroy(detectors.GetComponent<ConstantForceDetector>());
GameObject.Destroy(detectors.GetComponent<ConstantFluidDetector>()); GameObject.Destroy(detectors.GetComponent<ConstantFluidDetector>());
detectors.gameObject.AddComponent<DynamicForceDetector>(); var forceDetector = detectors.gameObject.AddComponent<DynamicForceDetector>();
detectors.gameObject.AddComponent<DynamicFluidDetector>(); detectors.gameObject.AddComponent<DynamicFluidDetector>();
detectors.layer = LayerMask.NameToLayer("BasicDetector");
var sphere = detectors.AddComponent<SphereCollider>();
sphere.radius = 1;
var sphere2 = detectors.AddComponent<SphereShape>();
sphere2._collisionMode = Shape.CollisionMode.Detector;
sphere2.radius = 1;
forceDetector._collider = sphere;
forceDetector._shape = sphere2;
} }
} }
} }

View File

@ -23,6 +23,7 @@ namespace NewHorizons.External
public bool IsTidallyLocked { get; set; } public bool IsTidallyLocked { get; set; }
public MVector3 AlignmentAxis { get; set; } public MVector3 AlignmentAxis { get; set; }
public bool ShowOrbitLine { get; set; } = true; public bool ShowOrbitLine { get; set; } = true;
public bool DottedOrbitLine { get; set; } = false;
public bool IsStatic { get; set; } public bool IsStatic { get; set; }
public MColor Tint { get; set; } public MColor Tint { get; set; }
public bool TrackingOrbitLine { get; set; } = false; public bool TrackingOrbitLine { get; set; } = false;

View File

@ -14,7 +14,7 @@ namespace NewHorizons.External
public RaftInfo[] Rafts; public RaftInfo[] Rafts;
public GeyserInfo[] Geysers; public GeyserInfo[] Geysers;
public TornadoInfo[] Tornados; public TornadoInfo[] Tornados;
public VolcanoInfo[] Volcanos; public VolcanoInfo[] Volcanoes;
public DialogueInfo[] Dialogue; public DialogueInfo[] Dialogue;
public RevealInfo[] Reveal; public RevealInfo[] Reveal;
public EntryLocationInfo[] EntryLocation; public EntryLocationInfo[] EntryLocation;
@ -33,8 +33,8 @@ namespace NewHorizons.External
public class DetailInfo public class DetailInfo
{ {
public string path; public string path;
public string objFilePath; public string objFilePath; //obsolete DO NOT DOCUMENT
public string mtlFilePath; public string mtlFilePath; //obsolete
public string assetBundle; public string assetBundle;
public MVector3 position; public MVector3 position;
public MVector3 rotation; public MVector3 rotation;
@ -67,6 +67,10 @@ namespace NewHorizons.External
public MVector3 position = null; public MVector3 position = null;
public MColor stoneTint = null; public MColor stoneTint = null;
public MColor lavaTint = null; public MColor lavaTint = null;
public float minLaunchSpeed = 50f;
public float maxLaunchSpeed = 150f;
public float minInterval = 5f;
public float maxInterval = 20f;
} }
public class DialogueInfo public class DialogueInfo
@ -76,6 +80,8 @@ namespace NewHorizons.External
public string xmlFile; public string xmlFile;
public MVector3 remoteTriggerPosition; public MVector3 remoteTriggerPosition;
public string blockAfterPersistentCondition; public string blockAfterPersistentCondition;
public string pathToAnimController;
public float lookAtRadius;
} }
public class RevealInfo public class RevealInfo

View File

@ -81,6 +81,8 @@ namespace NewHorizons
OnStarSystemLoaded = new StarSystemEvent(); OnStarSystemLoaded = new StarSystemEvent();
SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.sceneLoaded += OnSceneLoaded;
SceneManager.sceneUnloaded += OnSceneUnloaded;
Instance = this; Instance = this;
GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath); GlobalMessenger<DeathType>.AddListener("PlayerDeath", OnDeath);
GlobalMessenger.AddListener("WakeUp", new Callback(OnWakeUp)); GlobalMessenger.AddListener("WakeUp", new Callback(OnWakeUp));
@ -109,9 +111,7 @@ namespace NewHorizons
Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single)); Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single));
Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => _firstLoad = false); Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => _firstLoad = false);
Instance.ModHelper.Menus.PauseMenu.OnInit += DebugReload.InitializePauseMenu; Instance.ModHelper.Menus.PauseMenu.OnInit += DebugReload.InitializePauseMenu;
} }
public void OnDestroy() public void OnDestroy()
{ {
@ -127,12 +127,17 @@ namespace NewHorizons
Instance.OnStarSystemLoaded?.Invoke(Instance.CurrentStarSystem); Instance.OnStarSystemLoaded?.Invoke(Instance.CurrentStarSystem);
} }
void OnSceneLoaded(Scene scene, LoadSceneMode mode) private void OnSceneUnloaded(Scene scene)
{ {
Logger.Log($"Scene Loaded: {scene.name} {mode}");
SearchUtilities.ClearCache(); SearchUtilities.ClearCache();
ImageUtilities.ClearCache(); ImageUtilities.ClearCache();
AudioUtilities.ClearCache();
IsSystemReady = false;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Logger.Log($"Scene Loaded: {scene.name} {mode}");
_isChangingStarSystem = false; _isChangingStarSystem = false;

View File

@ -9,18 +9,38 @@ using UnityEngine.Networking;
namespace NewHorizons.Utility namespace NewHorizons.Utility
{ {
public static class AudioUtility public static class AudioUtilities
{ {
public static AudioClip LoadAudio(string filePath) private static Dictionary<string, AudioClip> _loadedAudioClips = new Dictionary<string, AudioClip>();
public static AudioClip LoadAudio(string path)
{ {
var task = Task.Run(async () => await GetAudioClip(filePath)); if (_loadedAudioClips.ContainsKey(path))
{
Logger.Log($"Already loaded audio at path: {path}");
return _loadedAudioClips[path];
}
Logger.Log($"Loading audio at path: {path}");
var task = Task.Run(async () => await GetAudioClip(path));
task.Wait(); task.Wait();
_loadedAudioClips.Add(path, task.Result);
return task.Result; return task.Result;
} }
public static void ClearCache()
{
Logger.Log("Clearing audio cache");
foreach (var audioClip in _loadedAudioClips.Values)
{
if (audioClip == null) continue;
UnityEngine.Object.Destroy(audioClip);
}
_loadedAudioClips.Clear();
}
private static async Task<AudioClip> GetAudioClip(string filePath) private static async Task<AudioClip> GetAudioClip(string filePath)
{ {
var extension = filePath.Split(new char[] { '.' }).Last(); var extension = filePath.Split(new char[] { '.' }).Last();
UnityEngine.AudioType audioType; UnityEngine.AudioType audioType;

View File

@ -8,6 +8,46 @@ namespace NewHorizons.Utility
{ {
static class ImageUtilities static class ImageUtilities
{ {
private static Dictionary<string, Texture2D> _loadedTextures = new Dictionary<string, Texture2D>();
private static List<Texture2D> _generatedTextures = new List<Texture2D>();
public static Texture2D GetTexture(IModBehaviour mod, string filename)
{
// Copied from OWML but without the print statement lol
var path = mod.ModHelper.Manifest.ModFolderPath + filename;
if (_loadedTextures.ContainsKey(path))
{
Logger.Log($"Already loaded image at path: {path}");
return _loadedTextures[path];
}
Logger.Log($"Loading image at path: {path}");
var data = File.ReadAllBytes(path);
var texture = new Texture2D(2, 2);
texture.name = Path.GetFileNameWithoutExtension(path);
texture.LoadImage(data);
_loadedTextures.Add(path, texture);
return texture;
}
public static void ClearCache()
{
Logger.Log("Cleaing image cache");
foreach (var texture in _loadedTextures.Values)
{
if (texture == null) continue;
UnityEngine.Object.Destroy(texture);
}
_loadedTextures.Clear();
foreach(var texture in _generatedTextures)
{
if (texture == null) continue;
UnityEngine.Object.Destroy(texture);
}
_generatedTextures.Clear();
}
public static Texture2D MakeOutline(Texture2D texture, Color color, int thickness) public static Texture2D MakeOutline(Texture2D texture, Color color, int thickness)
{ {
var outline = new Texture2D(texture.width, texture.height, TextureFormat.ARGB32, false); var outline = new Texture2D(texture.width, texture.height, TextureFormat.ARGB32, false);
@ -32,6 +72,8 @@ namespace NewHorizons.Utility
outline.SetPixels(outlinePixels); outline.SetPixels(outlinePixels);
outline.Apply(); outline.Apply();
_generatedTextures.Add(outline);
return outline; return outline;
} }
@ -67,6 +109,9 @@ namespace NewHorizons.Utility
newImage.name = image.name + "Tinted"; newImage.name = image.name + "Tinted";
newImage.SetPixels(pixels); newImage.SetPixels(pixels);
newImage.Apply(); newImage.Apply();
_generatedTextures.Add(newImage);
return newImage; return newImage;
} }
@ -84,15 +129,10 @@ namespace NewHorizons.Utility
newImage.name = image.name + "LerpedGrayscale"; newImage.name = image.name + "LerpedGrayscale";
newImage.SetPixels(pixels); newImage.SetPixels(pixels);
newImage.Apply(); newImage.Apply();
return newImage;
}
public static Texture2D LoadImage(string filepath) _generatedTextures.Add(newImage);
{
Texture2D tex = new Texture2D(2, 2); return newImage;
tex.name = Path.GetFileNameWithoutExtension(filepath);
tex.LoadRawTextureData(File.ReadAllBytes(filepath));
return tex;
} }
public static Texture2D ClearTexture(int width, int height) public static Texture2D ClearTexture(int width, int height)
@ -107,6 +147,9 @@ namespace NewHorizons.Utility
} }
tex.SetPixels(fillPixels); tex.SetPixels(fillPixels);
tex.Apply(); tex.Apply();
_generatedTextures.Add(tex);
return tex; return tex;
} }
@ -124,39 +167,12 @@ namespace NewHorizons.Utility
} }
tex.SetPixels(fillPixels); tex.SetPixels(fillPixels);
tex.Apply(); tex.Apply();
_generatedTextures.Add(tex);
return tex; return tex;
} }
private static Dictionary<string, Texture2D> _loadedTextures = new Dictionary<string, Texture2D>();
public static Texture2D GetTexture(IModBehaviour mod, string filename)
{
// Copied from OWML but without the print statement lol
var path = mod.ModHelper.Manifest.ModFolderPath + filename;
if (_loadedTextures.ContainsKey(path))
{
Logger.Log($"Already loaded image at path: {path}");
return _loadedTextures[path];
}
Logger.Log($"Loading image at path: {path}");
var data = File.ReadAllBytes(path);
var texture = new Texture2D(2, 2);
texture.name = Path.GetFileNameWithoutExtension(path);
texture.LoadImage(data);
_loadedTextures.Add(path, texture);
return texture;
}
public static void ClearCache()
{
foreach(var texture in _loadedTextures.Values)
{
if (texture == null) continue;
UnityEngine.Object.Destroy(texture);
}
_loadedTextures.Clear();
}
public static Color GetAverageColor(Texture2D src) public static Color GetAverageColor(Texture2D src)
{ {
var pixels = src.GetPixels32(); var pixels = src.GetPixels32();

View File

@ -14,6 +14,7 @@ namespace NewHorizons.Utility
public static void ClearCache() public static void ClearCache()
{ {
Logger.Log("Clearing search cache");
CachedGameObjects.Clear(); CachedGameObjects.Clear();
} }

View File

@ -3,7 +3,7 @@
"author": "xen, Bwc9876, & Book", "author": "xen, Bwc9876, & Book",
"name": "New Horizons", "name": "New Horizons",
"uniqueName": "xen.NewHorizons", "uniqueName": "xen.NewHorizons",
"version": "0.10.3", "version": "0.11.0",
"owmlVersion": "2.1.0", "owmlVersion": "2.1.0",
"conflicts": [ "Raicuparta.QuantumSpaceBuddies", "Vesper.OuterWildsMMO", "Vesper.AutoResume" ], "conflicts": [ "Raicuparta.QuantumSpaceBuddies", "Vesper.OuterWildsMMO", "Vesper.AutoResume" ],
"pathsToPreserve": [ "planets", "systems", "translations" ] "pathsToPreserve": [ "planets", "systems", "translations" ]

View File

@ -363,6 +363,10 @@
"default": false, "default": false,
"description": "Referring to the orbit line in the map screen." "description": "Referring to the orbit line in the map screen."
}, },
"dottedOrbitLine": {
"type": "boolean",
"default": false
},
"isStatic": { "isStatic": {
"type": "boolean", "type": "boolean",
"default": false, "default": false,
@ -603,14 +607,6 @@
"type": "string", "type": "string",
"description": "Relative filepath to an asset-bundle" "description": "Relative filepath to an asset-bundle"
}, },
"objFilePath": {
"type": "string",
"description": "Relative filepath to the obj file"
},
"mtlFilePath": {
"type": "string",
"description": "Relative filepath to the mtl file of the obj file"
},
"position": { "position": {
"$ref": "#/$defs/vector3" "$ref": "#/$defs/vector3"
}, },
@ -663,6 +659,15 @@
"blockAfterPersistentCondition": { "blockAfterPersistentCondition": {
"type": "string", "type": "string",
"description": "Prevents the dialogue from being created after a specific persistent condition is set. Useful for remote dialogue triggers that you want to have happen only once." "description": "Prevents the dialogue from being created after a specific persistent condition is set. Useful for remote dialogue triggers that you want to have happen only once."
},
"pathToAnimController": {
"type": "string",
"description": "If this dialogue is meant for a character, this is the relative path from the planet to that character's CharacterAnimController or SolanumAnimController."
},
"lookAtRadius": {
"type": "number",
"default": 0,
"description": "If a pathToAnimController is supplied, if you are within this distance the character will look at you. If it is set to 0, they will only look at you when spoken to."
} }
} }
} }
@ -747,6 +752,48 @@
} }
} }
} }
},
"volcanoes": {
"type": "array",
"description": "A set of meteor-spewing volcanoes",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"position": {
"$ref": "#/$defs/vector3",
"description": "The position of this volcano."
},
"stoneTint": {
"$ref": "#/$defs/color",
"description": "The colour of the meteor's stone."
},
"lavaTint": {
"$ref": "#/$defs/color",
"description": "The colour of the meteor's lava."
},
"minLaunchSpeed": {
"type": "number",
"description": "Minimum random speed at which meteors are launched.",
"default": 50
},
"maxLaunchSpeed": {
"type": "number",
"description": "Maximum random speed at which meteors are launched.",
"default": 150
},
"minInterval": {
"type": "number",
"description": "Minimum time between meteor launches.",
"default": 5
},
"maxInterval": {
"type": "number",
"description": "Maximum time between meteor launches.",
"default": 20
}
}
}
} }
} }
}, },

View File

@ -35,7 +35,7 @@ Check the ship's log for how to use your warp drive to travel between star syste
- Separate solar system scenes accessible via wormhole OR via the ship's new warp drive feature accessible via the ship's log - Separate solar system scenes accessible via wormhole OR via the ship's new warp drive feature accessible via the ship's log
- Remove existing planets - Remove existing planets
- Create planets from heightmaps/texturemaps - Create planets from heightmaps/texturemaps
- Create stars, comets, asteroid belts, satellites, geysers, cloak fields - Create stars, comets, asteroid belts, satellites, geysers, cloak fields, meteor-launching volcanoes
- Binary orbits - Binary orbits
- Signalscope signals and custom frequencies - Signalscope signals and custom frequencies
- Surface scatter: rocks, trees, etc, using in-game models, or custom ones - Surface scatter: rocks, trees, etc, using in-game models, or custom ones
@ -51,7 +51,6 @@ Check the ship's log for how to use your warp drive to travel between star syste
- Implement all planet features: - Implement all planet features:
- Tornados + floating islands - Tornados + floating islands
- Let any star go supernova - Let any star go supernova
- Meteors
- Pocket dimensions - Pocket dimensions
- Timed position/velocity changes - Timed position/velocity changes
- Implement custom Nomai scrolls - Implement custom Nomai scrolls

32
docs/Pipfile.lock generated
View File

@ -50,11 +50,11 @@
}, },
"click": { "click": {
"hashes": [ "hashes": [
"sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e", "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
"sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72" "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==8.1.2" "version": "==8.1.3"
}, },
"colorama": { "colorama": {
"hashes": [ "hashes": [
@ -74,11 +74,11 @@
}, },
"elementpath": { "elementpath": {
"hashes": [ "hashes": [
"sha256:2a432775e37a19e4362443078130a7dbfc457d7d093cd421c03958d9034cc08b", "sha256:1f41f1160aaae66bc25a8cb9451e5b31ca4553b6dccd9b57045205b005e5406e",
"sha256:3a27aaf3399929fccda013899cb76d3ff111734abf4281e5f9d3721ba0b9ffa3" "sha256:c556a9b9dde47fdf05bb3ad525dfb43fc6becb95532a053f6a73024e586ead37"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.5.0" "version": "==2.5.1"
}, },
"htmlmin": { "htmlmin": {
"hashes": [ "hashes": [
@ -96,11 +96,11 @@
}, },
"jinja2": { "jinja2": {
"hashes": [ "hashes": [
"sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119", "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
"sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9" "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==3.1.1" "version": "==3.1.2"
}, },
"json-minify": { "json-minify": {
"hashes": [ "hashes": [
@ -114,7 +114,7 @@
"sha256:66784a3d37c8f730588524cc8f103448847533f067ba8b5d76e7667675ee31f1", "sha256:66784a3d37c8f730588524cc8f103448847533f067ba8b5d76e7667675ee31f1",
"sha256:ed900db6b19b41bf681513c48ae5e403632878745775ddfc8d5b73438d2930fe" "sha256:ed900db6b19b41bf681513c48ae5e403632878745775ddfc8d5b73438d2930fe"
], ],
"markers": "python_version >= '3.7' and python_version < '4'", "markers": "python_version >= '3.7' and python_version < '4.0'",
"version": "==0.40.2" "version": "==0.40.2"
}, },
"jsonschema": { "jsonschema": {
@ -135,11 +135,11 @@
}, },
"markdown2": { "markdown2": {
"hashes": [ "hashes": [
"sha256:8f4ac8d9a124ab408c67361090ed512deda746c04362c36c2ec16190c720c2b0", "sha256:412520c7b6bba540c2c2067d6be3a523ab885703bf6a81d93963f848b55dfb9a",
"sha256:91113caf23aa662570fe21984f08fe74f814695c0a0ea8e863a8b4c4f63f9f6e" "sha256:f344d4adfba5d1de821f7850b36e3507f583468a7eb47e6fa191765ed0b9c66b"
], ],
"markers": "python_version >= '3.5' and python_version < '4'", "markers": "python_version >= '3.5' and python_version < '4.0'",
"version": "==2.4.2" "version": "==2.4.3"
}, },
"markupsafe": { "markupsafe": {
"hashes": [ "hashes": [
@ -222,7 +222,7 @@
"sha256:5053fc5ca7b8a281081274702ebf1584e341f40a68e6ab8f6b4b79f4b3fdf18e", "sha256:5053fc5ca7b8a281081274702ebf1584e341f40a68e6ab8f6b4b79f4b3fdf18e",
"sha256:8e8226f15c0b25565aa391797963b78c95930e12efc40e905153130783e766be" "sha256:8e8226f15c0b25565aa391797963b78c95930e12efc40e905153130783e766be"
], ],
"markers": "python_version >= '3.8' and python_version < '4'", "markers": "python_version >= '3.8' and python_version < '4.0'",
"version": "==0.1.0" "version": "==0.1.0"
}, },
"packaging": { "packaging": {
@ -453,7 +453,7 @@
"sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
"sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'",
"version": "==1.26.9" "version": "==1.26.9"
}, },
"xmlschema": { "xmlschema": {

View File

@ -2,6 +2,7 @@ Title: API
Sort_Priority: 40 Sort_Priority: 40
## How to use the API ## How to use the API
___
First create the following interface in your mod: First create the following interface in your mod:

View File

@ -2,6 +2,7 @@ Title: Detailing
Sort_Priority: 90 Sort_Priority: 90
## Details/Scatterer ## Details/Scatterer
___
For physical objects there are currently two ways of setting them up: specify an asset bundle and path to load a custom asset you created, or specify the path to the item you want to copy from the game in the scene hierarchy. Use the [Unity Explorer](https://outerwildsmods.com/mods/unityexplorer){ target="_blank" } mod to find an object you want to copy onto your new body. Some objects work better than others for this. Good luck. Some pointers: For physical objects there are currently two ways of setting them up: specify an asset bundle and path to load a custom asset you created, or specify the path to the item you want to copy from the game in the scene hierarchy. Use the [Unity Explorer](https://outerwildsmods.com/mods/unityexplorer){ target="_blank" } mod to find an object you want to copy onto your new body. Some objects work better than others for this. Good luck. Some pointers:
- Use "Object Explorer" to search - Use "Object Explorer" to search
@ -9,6 +10,7 @@ For physical objects there are currently two ways of setting them up: specify an
- Generally you can find planets by writing their name with no spaces/punctuation followed by "_Body". - Generally you can find planets by writing their name with no spaces/punctuation followed by "_Body".
## Asset Bundles ## Asset Bundles
___
Here is a template project: [Outer Wilds Unity Template](https://github.com/xen-42/outer-wilds-unity-template){ target="_blank" } Here is a template project: [Outer Wilds Unity Template](https://github.com/xen-42/outer-wilds-unity-template){ target="_blank" }
@ -47,10 +49,12 @@ public class CreateAssetBundles
6. Copy the asset bundle and asset bundle .manifest files from StreamingAssets into your mod's "planets" folder. If you did everything properly they should work in game. To double-check everything is included, open the .manifest file in a text editor to see the files included and their paths. 6. Copy the asset bundle and asset bundle .manifest files from StreamingAssets into your mod's "planets" folder. If you did everything properly they should work in game. To double-check everything is included, open the .manifest file in a text editor to see the files included and their paths.
## Importing a planet's surface from Unity ## Importing a planet's surface from Unity
___
Making a planet's entire surface from a Unity prefab is the exact same thing as adding one single big detail at position (0, 0, 0). Making a planet's entire surface from a Unity prefab is the exact same thing as adding one single big detail at position (0, 0, 0).
## Examples ## Examples
___
To add a Mars rover to the red planet in [RSS](https://github.com/xen-42/outer-wilds-real-solar-system), its model was put in an asset bundle as explained above, and then the following was put into the `Props` module: To add a Mars rover to the red planet in [RSS](https://github.com/xen-42/outer-wilds-real-solar-system), its model was put in an asset bundle as explained above, and then the following was put into the `Props` module:

View File

@ -2,6 +2,7 @@ Title: Dialogue
Sort_Priority: 50 Sort_Priority: 50
## Dialogue ## Dialogue
___
Here's an example dialogue XML: Here's an example dialogue XML:

View File

@ -5,10 +5,12 @@ Sort_Priority: 100
![New Horizons Logo]({{ 'images/home/home_logo.webp'|static }}) ![New Horizons Logo]({{ 'images/home/home_logo.webp'|static }})
# Outer Wilds New Horizons # Outer Wilds New Horizons
___
This is the official documentation for [New Horizons](https://github.com/xen-42/outer-wilds-new-horizons){ target="_blank" } This is the official documentation for [New Horizons](https://github.com/xen-42/outer-wilds-new-horizons){ target="_blank" }
## Getting Started ## Getting Started
___
Before starting, go into your in-game mod settings for New Horizons and switch Debug mode on. This allows you to: Before starting, go into your in-game mod settings for New Horizons and switch Debug mode on. This allows you to:
@ -114,11 +116,13 @@ To see all the different things you can put into a config file check out the [Ce
Check out the rest of the site for how to format [star system]({{ 'Star System Schema'|route}}), [dialogue]({{ 'Dialogue Schema'|route}}), [ship log]({{ 'Shiplog Schema'|route}}), and [translation]({{ 'Translation Schema'|route}}) files! Check out the rest of the site for how to format [star system]({{ 'Star System Schema'|route}}), [dialogue]({{ 'Dialogue Schema'|route}}), [ship log]({{ 'Shiplog Schema'|route}}), and [translation]({{ 'Translation Schema'|route}}) files!
## Publishing Your Mod ## Publishing Your Mod
___
Once your mod is complete, you can use the [addon creation tool](https://outerwildsmods.com/custom-worlds/create/){ target="_blank" } to upload your mod to the database. Once your mod is complete, you can use the [addon creation tool](https://outerwildsmods.com/custom-worlds/create/){ target="_blank" } to upload your mod to the database.
Alternatively, you can use the [planet creation template](https://github.com/xen-42/ow-new-horizons-config-template#readme){ target="_blank" } GitHub template if you're familiar with Git and GitHub Alternatively, you can use the [planet creation template](https://github.com/xen-42/ow-new-horizons-config-template#readme){ target="_blank" } GitHub template if you're familiar with Git and GitHub
## Helpful Resources ## Helpful Resources
___
The texturemap/heightmap feature was inspired by the Kerbal Space Program mod Kopernicus. A lot of the same techniques that apply to The texturemap/heightmap feature was inspired by the Kerbal Space Program mod Kopernicus. A lot of the same techniques that apply to
planet creation there apply to New Horizons. If you need help with planetary texturing, check out [The KSP texturing guide](https://forum.kerbalspaceprogram.com/index.php?/topic/165285-planetary-texturing-guide-repository/){ target="_blank" }. planet creation there apply to New Horizons. If you need help with planetary texturing, check out [The KSP texturing guide](https://forum.kerbalspaceprogram.com/index.php?/topic/165285-planetary-texturing-guide-repository/){ target="_blank" }.

View File

@ -3,6 +3,7 @@ Description: Hehe funny secret
Hide_In_Nav: True Hide_In_Nav: True
# Hello!! # Hello!!
___
Uh idk what to put here thought it would be funny haha Uh idk what to put here thought it would be funny haha

View File

@ -3,9 +3,11 @@ Description: A guide to editing the ship log in New Horizons
Sort_Priority: 70 Sort_Priority: 70
# Intro # Intro
___
Welcome! this page outlines how to create a custom ship log. Welcome! this page outlines how to create a custom ship log.
## Helpful Mods ## Helpful Mods
___
These mods are useful when developing your ship log These mods are useful when developing your ship log
@ -14,6 +16,7 @@ These mods are useful when developing your ship log
- [Save Editor](https://outerwildsmods.com/mods/saveeditor){ target="_blank" } - [Save Editor](https://outerwildsmods.com/mods/saveeditor){ target="_blank" }
## Helpful Tools ## Helpful Tools
___
These tools/references are highly recommended These tools/references are highly recommended
@ -24,10 +27,12 @@ These tools/references are highly recommended
- [The Examples Mod](https://github.com/xen-42/ow-new-horizons-examples){ target="_blank" } - [The Examples Mod](https://github.com/xen-42/ow-new-horizons-examples){ target="_blank" }
# Understanding Ship Logs # Understanding Ship Logs
___
First thing's first, I'll define some terminology regarding ship logs in the game, and how ship logs are structured. First thing's first, I'll define some terminology regarding ship logs in the game, and how ship logs are structured.
## Entries ## Entries
___
An entry is a card you see in rumor mode, it represents a specific area or concept in the game, such as Timber Hearth's An entry is a card you see in rumor mode, it represents a specific area or concept in the game, such as Timber Hearth's
village or the southern observatory on Brittle Hollow. village or the southern observatory on Brittle Hollow.
@ -53,6 +58,7 @@ Entries can be children of other entries, meaning they'll be smaller.
*The murals at the old settlement on Brittle Hollow are examples of child entries* *The murals at the old settlement on Brittle Hollow are examples of child entries*
## Rumor Facts ## Rumor Facts
___
A rumor fact represents the information you might hear about a specific area or concept, usually, you get these through A rumor fact represents the information you might hear about a specific area or concept, usually, you get these through
dialogue or maybe by observing a faraway planet. dialogue or maybe by observing a faraway planet.
@ -60,18 +66,21 @@ dialogue or maybe by observing a faraway planet.
![rumorFactExample]({{ "images/ship_log/rumor_example.webp"|static }}) ![rumorFactExample]({{ "images/ship_log/rumor_example.webp"|static }})
## Explore Facts ## Explore Facts
___
Explore facts represent the information you learn about a specific area or concept. Explore facts represent the information you learn about a specific area or concept.
![exploreFactExample]({{ "images/ship_log/explore_example.webp"|static }}) ![exploreFactExample]({{ "images/ship_log/explore_example.webp"|static }})
# The XML # The XML
___
Now that we know some terminology, let's get into how the XML works. Now that we know some terminology, let's get into how the XML works.
Every planet in the ship log is represented by a single XML file, you can see this if you use the unity explorer mod and Every planet in the ship log is represented by a single XML file, you can see this if you use the unity explorer mod and
navigate to ShipLogManager. navigate to ShipLogManager.
## Example File ## Example File
___
```xml ```xml
<!-- Example File --> <!-- Example File -->
@ -150,6 +159,7 @@ navigate to ShipLogManager.
``` ```
## Using The Schema ## Using The Schema
___
In the example XML, you may notice something like `xsi:noNamespaceSchemaLocation` at the top, this tells whatever editor In the example XML, you may notice something like `xsi:noNamespaceSchemaLocation` at the top, this tells whatever editor
you're using that the file at that link is the schema. The game simply ignores this though, so it won't be able to catch you're using that the file at that link is the schema. The game simply ignores this though, so it won't be able to catch
@ -158,6 +168,7 @@ Some editors may require you to [Trust](https://code.visualstudio.com/docs/edito
the schema file. Doing this varies per-editor, and you may also have to right-click the link and click download. the schema file. Doing this varies per-editor, and you may also have to right-click the link and click download.
## Loading The File ## Loading The File
___
You can load your XML file to your planet by doing adding the following to your planet's config You can load your XML file to your planet by doing adding the following to your planet's config
@ -172,6 +183,7 @@ You can load your XML file to your planet by doing adding the following to your
# Rumor Mode Options # Rumor Mode Options
## Entry Layout ## Entry Layout
___
By default, entries in rumor mode are laid out by rows, where each row is one planet. This will not make for a perfect By default, entries in rumor mode are laid out by rows, where each row is one planet. This will not make for a perfect
layout, so you can use the `entryPositions` property to change them layout, so you can use the `entryPositions` property to change them
@ -205,6 +217,7 @@ For example, if I want to change an entry with the ID of `EXAMPLE_ENTRY` and ano
*A set of entries laid out with auto mode* *A set of entries laid out with auto mode*
## Images ## Images
___
Custom entry images are a bit different from other custom images, instead of pointing to each file for each entry, you Custom entry images are a bit different from other custom images, instead of pointing to each file for each entry, you
point to a folder: point to a folder:
@ -224,6 +237,7 @@ you set alternate sprites by making a file with the entry's ID and `_ALT` at the
would be `EXAMPLE_ENTRY_ALT.png`. would be `EXAMPLE_ENTRY_ALT.png`.
## Curiosity Colors ## Curiosity Colors
___
Colors for each curiosity is given in a list, so if I wanted the curiosity `EXAMPLE_ENTRY` to have a color of blue: Colors for each curiosity is given in a list, so if I wanted the curiosity `EXAMPLE_ENTRY` to have a color of blue:
@ -256,8 +270,10 @@ Colors for each curiosity is given in a list, so if I wanted the curiosity `EXAM
*The curiosity's color is changed to blue* *The curiosity's color is changed to blue*
# Map Mode Options # Map Mode Options
___
## Layout ## Layout
___
Layout in map mode can be handled in two different ways, either manual or automatic, if you try to mix them you'll get Layout in map mode can be handled in two different ways, either manual or automatic, if you try to mix them you'll get
an error. an error.
@ -424,10 +440,12 @@ between Ash Twin and Ember Twin)
As you can see, they have similar properties to planets, with the addition of rotation As you can see, they have similar properties to planets, with the addition of rotation
# Revealing Facts # Revealing Facts
___
Of course, having a custom ship log is neat and all, but what use is it if the player can't unlock it? Of course, having a custom ship log is neat and all, but what use is it if the player can't unlock it?
## Initial Reveal ## Initial Reveal
___
You can set facts to reveal as soon as the player enters the system by adding the `initialReveal` property You can set facts to reveal as soon as the player enters the system by adding the `initialReveal` property
@ -443,6 +461,7 @@ You can set facts to reveal as soon as the player enters the system by adding th
``` ```
## Signal Discovery ## Signal Discovery
___
You can set a fact to reveal as soon as a signal is identified by editing the signal's `Reveals` attribute You can set a fact to reveal as soon as a signal is identified by editing the signal's `Reveals` attribute
@ -463,6 +482,7 @@ You can set a fact to reveal as soon as a signal is identified by editing the si
``` ```
## Dialogue ## Dialogue
___
You can set a fact to reveal in dialogue with the `<RevealFacts>` tag You can set a fact to reveal in dialogue with the `<RevealFacts>` tag
@ -484,6 +504,7 @@ You can set a fact to reveal in dialogue with the `<RevealFacts>` tag
``` ```
## Reveal Volumes ## Reveal Volumes
___
Reveal volumes are triggers/colliders in the world that can unlock facts from a variety of actions. Reveal volumes are triggers/colliders in the world that can unlock facts from a variety of actions.
Reveal volumes are specified in the `Props` module, its key is `reveal`. Reveal volumes are specified in the `Props` module, its key is `reveal`.
@ -551,6 +572,7 @@ trigger the reveal
``` ```
# Setting Entry Locations # Setting Entry Locations
___
Entry locations are the "Mark On HUD" option you see when in map mode, this allows the player to go back to where they Entry locations are the "Mark On HUD" option you see when in map mode, this allows the player to go back to where they
were in the event of the big funny. were in the event of the big funny.

View File

@ -2,6 +2,7 @@ Title: Translations
Sort_Priority: 60 Sort_Priority: 60
## Translations ## Translations
___
There are 12 supported languages in Outer Wilds: english, spanish_la, german, french, italian, polish, portuguese_br, japanese, russian, chinese_simple, korean, and turkish. There are 12 supported languages in Outer Wilds: english, spanish_la, german, french, italian, polish, portuguese_br, japanese, russian, chinese_simple, korean, and turkish.

View File

@ -2,6 +2,7 @@ Title: Update Planets
Sort_Priority: 80 Sort_Priority: 80
## Update Existing Planets ## Update Existing Planets
___
Similar to above, make a config where "Name" is the name of the planet. The name should be able to just match their in-game english names, however if you encounter any issues with that here are the in-code names for planets that are guaranteed to work: `SUN`, `CAVE_TWIN` (Ember Twin), `TOWER_TWIN` (Ash Twin), `TIMBER_HEARTH`, `BRITTLE_HOLLOW`, `GIANTS_DEEP`, `DARK_BRAMBLE`, `COMET` (Interloper), `WHITE_HOLE`, `WHITE_HOLE_TARGET` (Whitehole station I believe), `QUANTUM_MOON`, `ORBITAL_PROBE_CANNON`, `TIMBER_MOON` (Attlerock), `VOLCANIC_MOON` (Hollow's Lantern), `DREAMWORLD`, `MapSatellite`, `RINGWORLD` (the Stranger). Similar to above, make a config where "Name" is the name of the planet. The name should be able to just match their in-game english names, however if you encounter any issues with that here are the in-code names for planets that are guaranteed to work: `SUN`, `CAVE_TWIN` (Ember Twin), `TOWER_TWIN` (Ash Twin), `TIMBER_HEARTH`, `BRITTLE_HOLLOW`, `GIANTS_DEEP`, `DARK_BRAMBLE`, `COMET` (Interloper), `WHITE_HOLE`, `WHITE_HOLE_TARGET` (Whitehole station I believe), `QUANTUM_MOON`, `ORBITAL_PROBE_CANNON`, `TIMBER_MOON` (Attlerock), `VOLCANIC_MOON` (Hollow's Lantern), `DREAMWORLD`, `MapSatellite`, `RINGWORLD` (the Stranger).
@ -20,6 +21,7 @@ You can also delete parts of an existing planet. Here's part of an example confi
In `childrenToDestroy` you list the relative paths for the children of the planet's gameObject that you want to delete. In `childrenToDestroy` you list the relative paths for the children of the planet's gameObject that you want to delete.
## Destroy Existing Planets ## Destroy Existing Planets
___
You do this (but with the appropriate name) as its own config. You do this (but with the appropriate name) as its own config.
```json ```json