diff --git a/Heads/Changelog.txt b/Heads/Changelog.txt
new file mode 100644
index 0000000..3729537
--- /dev/null
+++ b/Heads/Changelog.txt
@@ -0,0 +1,3 @@
+**v0.1.0**
+
+- First Beta Release
diff --git a/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.dll b/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.dll
new file mode 100644
index 0000000..0c62e18
Binary files /dev/null and b/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.dll differ
diff --git a/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.version b/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.version
new file mode 100644
index 0000000..eb4eea0
--- /dev/null
+++ b/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.version
@@ -0,0 +1,25 @@
+{
+ "NAME": "Sigma Replacements: Heads",
+ "URL": "https://raw.githubusercontent.com/Sigma88/Sigma-Replacements/master/Heads/GameData/Sigma/Replacements/Heads/Plugins/SigmaReplacementsHeads.version",
+ "DOWNLOAD": "http://forum.kerbalspaceprogram.com/index.php?/topic/167233-0",
+ "CHANGE_LOG_URL": "https://raw.githubusercontent.com/Sigma88/Sigma-Replacements/master/Heads/Changelog.txt",
+ "GITHUB":
+ {
+ "USERNAME": "Sigma88",
+ "REPOSITORY": "Sigma-Replacements",
+ "ALLOW_PRE_RELEASE": false
+ },
+ "VERSION":
+ {
+ "MAJOR": 0,
+ "MINOR": 1,
+ "PATCH": 0,
+ "BUILD": 0
+ },
+ "KSP_VERSION":
+ {
+ "MAJOR": 1,
+ "MINOR": 3,
+ "PATCH": 1
+ }
+}
diff --git a/Heads/License.txt b/Heads/License.txt
new file mode 100644
index 0000000..247dae2
--- /dev/null
+++ b/Heads/License.txt
@@ -0,0 +1,8 @@
+Sigma Replacements: Heads by Sigma88 is released under the following license:
+
+
+All Rights Reserved
+
+
+For more info visit the KSP Forum Thread:
+http://forum.kerbalspaceprogram.com/index.php?/topic/167233-0
diff --git a/Heads/README.md b/Heads/README.md
new file mode 100644
index 0000000..2703431
--- /dev/null
+++ b/Heads/README.md
@@ -0,0 +1,11 @@
+# Sigma Replacements: Heads
+
+
+**Customizeable Crew Heads**
+
+
+KSP Forum Thread: http://forum.kerbalspaceprogram.com/index.php?/topic/167233-0/
+
+Download Latest Release: https://github.com/Sigma88/Sigma-Replacements/releases
+
+Dev version: https://github.com/Sigma88/Sigma-Replacements/tree/Heads
diff --git a/README.md b/README.md
index 6f32795..c06170e 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
# Sigma Replacements
-**Hanles replacement of various KSP assets**
+**Handles replacement of various KSP assets**
-KSP Forum Thread: http://forum.kerbalspaceprogram.com/index.php?/topic/-0/
+KSP Forum Thread: http://forum.kerbalspaceprogram.com/index.php?/topic/167233-0/
Download Latest Release: https://github.com/Sigma88/Sigma-KerbalReplacements/releases/latest
Dev versions:
-- *Heads* https://github.com/Sigma88/Sigma-Replacements/tree/Heads
-- *Suits* https://github.com/Sigma88/Sigma-Replacements/tree/Suits
-- *Textures* https://github.com/Sigma88/Sigma-Replacements/tree/Textures
+- Heads - https://github.com/Sigma88/Sigma-Replacements/tree/Heads
+- Suits - https://github.com/Sigma88/Sigma-Replacements/tree/Suits
+- Textures - https://github.com/Sigma88/Sigma-Replacements/tree/Textures
diff --git a/[Source]/Distribution/SigmaReplacementsHeads.dll b/[Source]/Distribution/SigmaReplacementsHeads.dll
new file mode 100644
index 0000000..0c62e18
Binary files /dev/null and b/[Source]/Distribution/SigmaReplacementsHeads.dll differ
diff --git a/[Source]/SigmaReplacements/Heads/CustomHead.cs b/[Source]/SigmaReplacements/Heads/CustomHead.cs
new file mode 100644
index 0000000..119eddf
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/CustomHead.cs
@@ -0,0 +1,223 @@
+using System.Linq;
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ internal class CustomHead : MonoBehaviour
+ {
+ // Colors
+ Color? pupilLeft = null;
+ Color? pupilRight = null;
+ Color? eyeballLeft = null;
+ Color? eyeballRight = null;
+ Color? upTeeth01 = null;
+ Color? upTeeth02 = null;
+ Color? tongue = null;
+ Color? head = null;
+ Color? hair = null;
+ Color? arm = null;
+
+ // Textures
+ Texture pupilLeftTex = null;
+ Texture pupilRightTex = null;
+ Texture eyeballLeftTex = null;
+ Texture eyeballRightTex = null;
+ Texture upTeeth01Tex = null;
+ Texture upTeeth02Tex = null;
+ Texture tongueTex = null;
+ Texture headTex = null;
+ Texture hairTex = null;
+ Texture armTex = null;
+
+
+ // Normals
+ Texture pupilLeftNrm = null;
+ Texture pupilRightNrm = null;
+ Texture eyeballLeftNrm = null;
+ Texture eyeballRightNrm = null;
+ Texture upTeeth01Nrm = null;
+ Texture upTeeth02Nrm = null;
+ Texture tongueNrm = null;
+ Texture headNrm = null;
+ Texture hairNrm = null;
+ Texture armNrm = null;
+
+
+ void Start()
+ {
+ Debug.Log("CustomHead.Start", "In gameObject = " + gameObject);
+ Apply();
+ }
+
+ internal void Apply()
+ {
+ Debug.Log("CustomHead.Apply", "In gameObject = " + gameObject);
+
+ ProtoCrewMember kerbal = GetComponent()?.part?.protoModuleCrew?.FirstOrDefault();
+ if (kerbal == null) kerbal = GetComponent()?.protoCrewMember;
+ if (kerbal == null) kerbal = GetComponent()?.crewMember;
+ if (kerbal == null) kerbal = GetComponent()?.crewMember;
+ if (kerbal == null) kerbal = GetComponent()?.crewMember;
+ if (kerbal == null) kerbal = GetComponent()?.crewMember;
+ Debug.Log("CustomHead.Apply", "kerbal = " + kerbal);
+ if (kerbal == null) return;
+
+ LoadFor(kerbal);
+
+ ApplyTo(kerbal);
+ }
+
+ void LoadFor(ProtoCrewMember kerbal)
+ {
+ Debug.Log("CustomHead.LoadFor", "kerbal = " + kerbal);
+
+ HeadInfo.hash = "";
+ int? useChance = null;
+
+ for (int i = 0; i < HeadInfo.DataBase?.Count; i++)
+ {
+ HeadInfo info = HeadInfo.DataBase[i].GetFor(kerbal);
+ string collection = "";
+
+ if (info != null)
+ {
+ if (string.IsNullOrEmpty(collection) || collection == info.collection)
+ {
+ if (info.useChance != 1)
+ useChance = kerbal.Hash(info.useGameSeed) % 100;
+
+ if (info.useChance == 1 || useChance < info.useChance * 100)
+ {
+ // Collection
+ collection = info.collection;
+
+ // Colors
+ pupilLeft = pupilLeft ?? info.pupilLeft.Pick(kerbal, info.useGameSeed);
+ pupilRight = pupilRight ?? info.pupilRight.At(pupilLeft, info.pupilLeft) ?? info.pupilRight.Pick(kerbal, info.useGameSeed);
+ eyeballLeft = eyeballLeft ?? info.eyeballLeft.Pick(kerbal, info.useGameSeed);
+ eyeballRight = eyeballRight ?? info.eyeballRight.At(eyeballLeft, info.eyeballLeft) ?? info.eyeballRight.Pick(kerbal, info.useGameSeed);
+ upTeeth01 = upTeeth01 ?? info.upTeeth01.Pick(kerbal, info.useGameSeed);
+ upTeeth02 = upTeeth02 ?? info.upTeeth02.At(upTeeth01, info.upTeeth01) ?? info.upTeeth02.Pick(kerbal, info.useGameSeed);
+ tongue = tongue ?? info.tongue.Pick(kerbal, info.useGameSeed);
+ head = head ?? info.head.Pick(kerbal, info.useGameSeed);
+ hair = hair ?? info.hair.At(head, info.head) ?? info.hair.Pick(kerbal, info.useGameSeed);
+ arm = arm ?? info.arm.Pick(kerbal, info.useGameSeed);
+
+ // Textures
+ pupilLeftTex = pupilLeftTex ?? info.pupilLeftTex.Pick(kerbal, info.useGameSeed);
+ pupilRightTex = pupilRightTex ?? info.pupilRightTex.At(pupilLeftTex, info.pupilLeftTex) ?? info.pupilRightTex.Pick(kerbal, info.useGameSeed);
+ eyeballLeftTex = eyeballLeftTex ?? info.eyeballLeftTex.Pick(kerbal, info.useGameSeed);
+ eyeballRightTex = eyeballRightTex ?? info.eyeballRightTex.At(eyeballLeftTex, info.eyeballLeftTex) ?? info.eyeballRightTex.Pick(kerbal, info.useGameSeed);
+ upTeeth01Tex = upTeeth01Tex ?? info.upTeeth01Tex.Pick(kerbal, info.useGameSeed);
+ upTeeth02Tex = upTeeth02Tex ?? info.upTeeth02Tex.At(upTeeth01Tex, info.upTeeth01Tex) ?? info.upTeeth02Tex.Pick(kerbal, info.useGameSeed);
+ tongueTex = tongueTex ?? info.tongueTex.Pick(kerbal, info.useGameSeed);
+ headTex = headTex ?? info.headTex.Pick(kerbal, info.useGameSeed);
+ hairTex = hairTex ?? info.hairTex.At(headTex, info.headTex) ?? info.hairTex.Pick(kerbal, info.useGameSeed);
+ armTex = armTex ?? info.armTex.Pick(kerbal, info.useGameSeed);
+
+ // Normals
+ pupilLeftNrm = pupilLeftNrm ?? info.pupilLeftNrm.At(pupilLeftTex, info.pupilLeftTex) ?? info.pupilLeftNrm.Pick(kerbal, info.useGameSeed);
+ pupilRightNrm = pupilRightNrm ?? info.pupilRightNrm.At(pupilRightTex, info.pupilRightTex) ?? info.pupilRightNrm.Pick(kerbal, info.useGameSeed);
+ eyeballLeftNrm = eyeballLeftNrm ?? info.eyeballLeftNrm.At(eyeballLeftTex, info.eyeballLeftTex) ?? info.eyeballLeftNrm.Pick(kerbal, info.useGameSeed);
+ eyeballRightNrm = eyeballRightNrm ?? info.eyeballRightNrm.At(eyeballRightTex, info.eyeballRightTex) ?? info.eyeballRightNrm.Pick(kerbal, info.useGameSeed);
+ upTeeth01Nrm = upTeeth01Nrm ?? info.upTeeth01Nrm.At(upTeeth01Tex, info.upTeeth01Tex) ?? info.upTeeth01Nrm.Pick(kerbal, info.useGameSeed);
+ upTeeth02Nrm = upTeeth02Nrm ?? info.upTeeth02Nrm.At(upTeeth02Tex, info.upTeeth02Tex) ?? info.upTeeth02Nrm.Pick(kerbal, info.useGameSeed);
+ tongueNrm = tongueNrm ?? info.tongueNrm.At(tongueTex, info.tongueTex) ?? info.tongueNrm.Pick(kerbal, info.useGameSeed);
+ headNrm = headNrm ?? info.headNrm.At(headTex, info.headTex) ?? info.headNrm.Pick(kerbal, info.useGameSeed);
+ hairNrm = hairNrm ?? info.hairNrm.At(hairTex, info.hairTex) ?? info.hairNrm.Pick(kerbal, info.useGameSeed);
+ armNrm = armNrm ?? info.armNrm.At(armTex, info.armTex) ?? info.armNrm.Pick(kerbal, info.useGameSeed);
+ }
+ }
+ }
+ }
+ }
+
+ void ApplyTo(ProtoCrewMember kerbal)
+ {
+ Debug.Log("CustomHead.ApplyTo", "kerbal = " + kerbal);
+
+ Renderer[] renderers = GetComponentsInChildren();
+
+ for (int i = 0; i < renderers?.Length; i++)
+ {
+ string name = renderers[i]?.name;
+ Material material = renderers[i]?.material;
+ if (material == null) continue;
+
+ if (name == "pupilLeft" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_pupilLeft")
+ {
+ material.SetColor(pupilLeft);
+ material.SetTexture(pupilLeftTex);
+ material.SetNormal(pupilLeftNrm);
+ }
+
+ if (name == "pupilRight" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_pupilRight")
+ {
+ material.SetColor(pupilRight);
+ material.SetTexture(pupilRightTex);
+ material.SetNormal(pupilRightNrm);
+ }
+
+ if (name == "eyeballLeft" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_eyeballLeft")
+ {
+ material.SetColor(eyeballLeft);
+ material.SetTexture(eyeballLeftTex);
+ material.SetNormal(eyeballLeftNrm);
+ }
+
+ if (name == "eyeballRight" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_eyeballRight")
+ {
+ material.SetColor(eyeballRight);
+ material.SetTexture(eyeballRightTex);
+ material.SetNormal(eyeballRightNrm);
+ }
+
+ if (name == "upTeeth01" || name == "downTeeth01" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_downTeeth01")
+ {
+ material.SetColor(upTeeth01);
+ material.SetTexture(upTeeth01Tex);
+ material.SetNormal(upTeeth01Nrm);
+ }
+
+ if (name == "upTeeth02" || name == "upTeeth01" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_upTeeth01")
+ {
+ material.SetColor(upTeeth02);
+ material.SetTexture(upTeeth02Tex);
+ material.SetNormal(upTeeth02Nrm);
+ }
+
+ if (name == "tongue")
+ {
+ material.SetColor(tongue);
+ material.SetTexture(tongueTex);
+ material.SetNormal(tongueNrm);
+ }
+
+ if (name == "headMesh01" || name == "headMesh" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_polySurface51")
+ {
+ material.SetColor(head);
+ material.SetTexture(headTex);
+ material.SetNormal(headNrm);
+ }
+
+ if (name == "ponytail" || name == "mesh_female_kerbalAstronaut01_kerbalGirl_mesh_pCube1")
+ {
+ material.SetColor(hair);
+ material.SetTexture(hairTex);
+ material.SetNormal(hairNrm);
+ }
+
+ if (name == "hand_left01" || name == "hand_right01")
+ {
+ material.SetColor(arm);
+ material.SetTexture(armTex);
+ material.SetNormal(armNrm);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/DebugLogger.cs b/[Source]/SigmaReplacements/Heads/DebugLogger.cs
new file mode 100644
index 0000000..cab95b5
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/DebugLogger.cs
@@ -0,0 +1,51 @@
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ internal static class Debug
+ {
+ internal static bool debug = false;
+ internal static string Tag = "[SigmaLog SR]";
+
+ internal static void Log(string message)
+ {
+ if (debug)
+ {
+ UnityEngine.Debug.Log(Tag + ": " + message);
+ }
+ }
+
+ internal static void Log(string Method, string message)
+ {
+ if (debug)
+ {
+ UnityEngine.Debug.Log(Tag + " " + Method + ": " + message);
+ }
+ }
+ }
+
+ [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ class DebugWarning : MonoBehaviour
+ {
+ void Start()
+ {
+ if (Debug.debug)
+ {
+ PopupDialog.SpawnPopupDialog
+ (
+ new Vector2(0.5f, 0.5f),
+ new Vector2(0.5f, 0.5f),
+ UserSettings.nodeName,
+ UserSettings.nodeName + " Warning",
+ "\nDebug Spam is activated.\n\n" +
+ "This feature will greatly affect performance:\n" +
+ "use it only for debugging purposes.",
+ "OK",
+ true,
+ UISkinManager.GetSkin("MainMenuSkin")
+ );
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/Extensions.cs b/[Source]/SigmaReplacements/Heads/Extensions.cs
new file mode 100644
index 0000000..b2b964c
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/Extensions.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ internal static class Extensions
+ {
+ internal static void Load(this CrewMember[] array, ConfigNode node, int index)
+ {
+ CrewMember kerbal = array[index];
+ HeadInfo stats = new HeadInfo(node.GetNode("Stats") ?? new ConfigNode(), new ConfigNode());
+
+ array[index] = new CrewMember
+ (
+ stats?.rosterStatus ?? kerbal.type,
+ !string.IsNullOrEmpty(stats?.name) ? stats.name : kerbal.name,
+ stats?.gender ?? kerbal.gender,
+ stats?.trait?.Length > 0 && !string.IsNullOrEmpty(stats.trait[0]) ? stats.trait[0] : kerbal.trait,
+ stats?.veteran ?? kerbal.veteran,
+ stats?.isBadass ?? kerbal.isBadass,
+ stats?.courage ?? kerbal.courage,
+ stats?.stupidity ?? kerbal.stupidity,
+ stats?.experienceLevel ?? kerbal.experienceLevel
+ );
+ }
+
+ internal static void SetColor(this Material material, Color? color)
+ {
+ if (material != null && color != null)
+ {
+ material.color = (Color)color;
+ }
+ }
+
+ internal static void SetTexture(this Material material, Texture newTex)
+ {
+ if (material != null && newTex != null)
+ {
+ Texture oldTex = material?.mainTexture;
+
+ if (oldTex != null)
+ {
+ newTex.anisoLevel = oldTex.anisoLevel;
+ newTex.wrapMode = oldTex.wrapMode;
+ }
+
+ material.mainTexture = newTex;
+ }
+ }
+
+ internal static void SetNormal(this Material material, Texture newTex)
+ {
+ if (material != null && newTex != null)
+ {
+ material.shader = Shader.Find("Bumped Diffuse");
+
+ Texture oldTex = material.GetTexture("_BumpMap");
+
+ if (oldTex != null)
+ {
+ newTex.anisoLevel = oldTex.anisoLevel;
+ newTex.wrapMode = oldTex.wrapMode;
+ }
+
+ material.SetTexture("_BumpMap", newTex);
+ }
+ }
+
+ internal static Texture At(this List right, Texture item, List left)
+ {
+ if (item != null && left.Contains(item) && right?.Count > left.IndexOf(item))
+ return right[left.IndexOf(item)];
+ return null;
+ }
+
+ internal static Color? At(this List right, Color? item, List left)
+ {
+ if (item != null && left.Contains((Color)item) && right?.Count > left.IndexOf((Color)item))
+ return right[left.IndexOf((Color)item)];
+ return null;
+ }
+
+ internal static Texture Pick(this List list, ProtoCrewMember kerbal, bool useGameSeed)
+ {
+ if (list.Count == 1)
+ return list[0];
+ else if (list.Count > 1)
+ return list[kerbal.Hash(useGameSeed) % list.Count];
+ else
+ return null;
+ }
+
+ internal static Color? Pick(this List list, ProtoCrewMember kerbal, bool useGameSeed)
+ {
+ if (list.Count == 1)
+ return list[0];
+ else if (list.Count > 1)
+ return list[kerbal.Hash(useGameSeed) % list.Count];
+ else
+ return null;
+ }
+
+ internal static int Hash(this ProtoCrewMember kerbal, bool useGameSeed)
+ {
+ string hash = HeadInfo.hash;
+
+ if (string.IsNullOrEmpty(hash)) hash = kerbal.name;
+
+ int h = Math.Abs(hash.GetHashCode());
+
+ if (useGameSeed && HighLogic.CurrentGame != null) h += Math.Abs(HighLogic.CurrentGame.Seed);
+
+ HeadInfo.hash = h.ToString();
+
+ return h;
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/HeadInfo.cs b/[Source]/SigmaReplacements/Heads/HeadInfo.cs
new file mode 100644
index 0000000..f74ddae
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/HeadInfo.cs
@@ -0,0 +1,338 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEngine;
+using Gender = ProtoCrewMember.Gender;
+using Type = ProtoCrewMember.KerbalType;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ internal class HeadInfo
+ {
+ // Static
+ internal static string hash = "";
+ internal static List List = new List();
+ internal static List DataBase = new List();
+
+ // Identifiers
+ internal string name = null;
+
+ // Requirements
+ internal bool useGameSeed = false;
+ internal float useChance = 1;
+ internal Type? rosterStatus = null;
+ internal Gender? gender = null;
+ internal string[] trait = null;
+ internal bool? veteran = null;
+ internal bool? isBadass = null;
+ int minLevel = 0;
+ int maxLevel = 5;
+ float minCourage = 0;
+ float maxCourage = 1;
+ float minStupidity = 0;
+ float maxStupidity = 1;
+ // For MainMenuKerbals
+ internal float? courage = null;
+ internal float? stupidity = null;
+ internal int? experienceLevel = null;
+
+ // Collection
+ internal string collection = "";
+
+ // Colors Lists
+ internal List pupilLeft = new List();
+ internal List pupilRight = new List();
+ internal List eyeballLeft = new List();
+ internal List eyeballRight = new List();
+ internal List upTeeth01 = new List();
+ internal List upTeeth02 = new List();
+ internal List tongue = new List();
+ internal List head = new List();
+ internal List hair = new List();
+ internal List arm = new List();
+
+ // Textures Lists
+ internal List pupilLeftTex = new List();
+ internal List pupilRightTex = new List();
+ internal List eyeballLeftTex = new List();
+ internal List eyeballRightTex = new List();
+ internal List upTeeth01Tex = new List();
+ internal List upTeeth02Tex = new List();
+ internal List tongueTex = new List();
+ internal List headTex = new List();
+ internal List hairTex = new List();
+ internal List armTex = new List();
+
+ // Normals Lists
+ internal List pupilLeftNrm = new List();
+ internal List pupilRightNrm = new List();
+ internal List eyeballLeftNrm = new List();
+ internal List eyeballRightNrm = new List();
+ internal List upTeeth01Nrm = new List();
+ internal List upTeeth02Nrm = new List();
+ internal List tongueNrm = new List();
+ internal List headNrm = new List();
+ internal List hairNrm = new List();
+ internal List armNrm = new List();
+
+
+ // Get
+ internal HeadInfo GetFor(ProtoCrewMember kerbal)
+ {
+ if (name == null || name == kerbal.name)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched name = " + name + " to kerbal name = " + kerbal.name);
+ if (rosterStatus == null || rosterStatus == kerbal.type)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched rosterStatus = " + rosterStatus + " to kerbal rosterStatus = " + kerbal.type);
+ if (gender == null || gender == kerbal.gender)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched gender = " + gender + " to kerbal gender = " + kerbal.gender);
+ if (trait == null || trait.Contains(kerbal.trait))
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched trait = " + trait + " to kerbal trait = " + kerbal.trait);
+ if (veteran == null || veteran == kerbal.veteran)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched veteran = " + veteran + " to kerbal veteran = " + kerbal.veteran);
+ if (isBadass == null || isBadass == kerbal.isBadass)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched isBadass = " + isBadass + " to kerbal isBadass = " + kerbal.isBadass);
+ if (minLevel <= kerbal.experienceLevel && maxLevel >= kerbal.experienceLevel)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched minLevel = " + minLevel + ", maxLevel = " + maxLevel + " to kerbal level = " + kerbal.experienceLevel);
+ if (minCourage <= kerbal.courage && maxCourage >= kerbal.courage)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched minCourage = " + minCourage + ", maxCourage = " + maxCourage + " to kerbal courage = " + kerbal.courage);
+ if (minStupidity <= kerbal.stupidity && maxStupidity >= kerbal.stupidity)
+ {
+ Debug.Log("HeadInfo.GetFor", "Matched minStupidity = " + minStupidity + ", maxStupidity = " + maxStupidity + " to kerbal stupidity = " + kerbal.stupidity);
+ Debug.Log("HeadInfo.GetFor", "Return this HeadInfo");
+ return this;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Debug.Log("HeadInfo.GetFor", "Return null");
+ return null;
+ }
+
+
+ // New HeadInfo
+ internal HeadInfo(ConfigNode requirements, ConfigNode info)
+ {
+ Debug.Log("HeadInfo", "new HeadInfo from:");
+ Debug.Log("HeadInfo", "Requirements node = " + requirements);
+ Debug.Log("HeadInfo", "Head node = " + info);
+
+ // Parse HeadInfo Requirements
+ useGameSeed = Parse(requirements.GetValue("useGameSeed"), useGameSeed);
+ useChance = Parse(requirements.GetValue("useChance"), useChance);
+ name = requirements.GetValue("name");
+ rosterStatus = Parse(requirements.GetValue("rosterStatus"), rosterStatus);
+ gender = Parse(requirements.GetValue("gender"), gender);
+ trait = requirements.HasValue("trait") ? requirements.GetValues("trait") : null;
+ veteran = Parse(requirements.GetValue("veteran"), veteran);
+ isBadass = Parse(requirements.GetValue("isBadass"), isBadass);
+ minLevel = Parse(requirements.GetValue("minLevel"), minLevel);
+ maxLevel = Parse(requirements.GetValue("maxLevel"), maxLevel);
+ minCourage = Parse(requirements.GetValue("minCourage"), minCourage);
+ maxCourage = Parse(requirements.GetValue("maxCourage"), maxCourage);
+ minStupidity = Parse(requirements.GetValue("minStupidity"), minStupidity);
+ maxStupidity = Parse(requirements.GetValue("maxStupidity"), maxStupidity);
+ // For MainMenuKerbals
+ experienceLevel = Parse(requirements.GetValue("level"), experienceLevel);
+ courage = Parse(requirements.GetValue("courage"), courage);
+ stupidity = Parse(requirements.GetValue("stupidity"), stupidity);
+
+
+ // Parse Collection
+ collection = info.GetValue("collection");
+
+ // Parse HeadInfo Colors
+ pupilLeft = Parse(info.GetValues("pupilLeft"), pupilLeft);
+ pupilRight = Parse(info.GetValues("pupilRight"), pupilRight);
+ eyeballLeft = Parse(info.GetValues("eyeballLeft"), eyeballLeft);
+ eyeballRight = Parse(info.GetValues("eyeballRight"), eyeballRight);
+ upTeeth01 = Parse(info.GetValues("upTeeth01"), upTeeth01);
+ upTeeth02 = Parse(info.GetValues("upTeeth02"), upTeeth02);
+ tongue = Parse(info.GetValues("tongue"), tongue);
+ head = Parse(info.GetValues("head"), head);
+ hair = Parse(info.GetValues("hair"), hair);
+ arm = Parse(info.GetValues("arm"), arm);
+
+ // Parse HeadInfo Textures
+ pupilLeftTex = Parse(info.GetValues("pupilLeftTex"), pupilLeftTex);
+ pupilRightTex = Parse(info.GetValues("pupilRightTex"), pupilRightTex);
+ eyeballLeftTex = Parse(info.GetValues("eyeballLeftTex"), eyeballLeftTex);
+ eyeballRightTex = Parse(info.GetValues("eyeballRightTex"), eyeballRightTex);
+ upTeeth01Tex = Parse(info.GetValues("upTeeth01Tex"), upTeeth01Tex);
+ upTeeth02Tex = Parse(info.GetValues("upTeeth02Tex"), upTeeth02Tex);
+ tongueTex = Parse(info.GetValues("tongueTex"), tongueTex);
+ headTex = Parse(info.GetValues("headTex"), headTex);
+ hairTex = Parse(info.GetValues("hairTex"), hairTex);
+ armTex = Parse(info.GetValues("armTex"), armTex);
+
+ // Parse HeadInfo Normals
+ pupilLeftNrm = Parse(info.GetValues("pupilLeftNrm"), pupilLeftNrm);
+ pupilRightNrm = Parse(info.GetValues("pupilRightNrm"), pupilRightNrm);
+ eyeballLeftNrm = Parse(info.GetValues("eyeballLeftNrm"), eyeballLeftNrm);
+ eyeballRightNrm = Parse(info.GetValues("eyeballRightNrm"), eyeballRightNrm);
+ upTeeth01Nrm = Parse(info.GetValues("upTeeth01Nrm"), upTeeth01Nrm);
+ upTeeth02Nrm = Parse(info.GetValues("upTeeth02Nrm"), upTeeth02Nrm);
+ tongueNrm = Parse(info.GetValues("tongueNrm"), tongueNrm);
+ headNrm = Parse(info.GetValues("headNrm"), headNrm);
+ hairNrm = Parse(info.GetValues("hairNrm"), hairNrm);
+ armNrm = Parse(info.GetValues("armNrm"), armNrm);
+
+ // Parse Folders
+ ParseFolders(info.GetNode("Folders"));
+ }
+
+
+ // Parsers
+ float Parse(string s, float defaultValue) { return float.TryParse(s, out float f) ? f : defaultValue; }
+ float? Parse(string s, float? defaultValue) { return float.TryParse(s, out float f) ? f : defaultValue; }
+ bool Parse(string s, bool defaultValue) { return bool.TryParse(s, out bool b) ? b : defaultValue; }
+ bool? Parse(string s, bool? defaultValue) { return bool.TryParse(s, out bool b) ? b : defaultValue; }
+ int Parse(string s, int defaultValue) { return int.TryParse(s, out int b) ? b : defaultValue; }
+ int? Parse(string s, int? defaultValue) { return int.TryParse(s, out int b) ? b : defaultValue; }
+
+ Type? Parse(string s, Type? defaultValue)
+ {
+ try { return (Type)Enum.Parse(typeof(Type), s); }
+ catch { return defaultValue; }
+ }
+
+ Gender? Parse(string s, Gender? defaultValue)
+ {
+ try { return (Gender)Enum.Parse(typeof(Gender), s); }
+ catch { return defaultValue; }
+ }
+
+ Texture Parse(string s, Texture defaultValue)
+ {
+ return Resources.FindObjectsOfTypeAll().FirstOrDefault(t => t.name == s) ?? defaultValue;
+ }
+
+ List Parse(string[] s, List defaultValue)
+ {
+ for (int i = 0; i < s.Length; i++)
+ {
+ Texture tex = null;
+ tex = Parse(s[i], tex);
+ if (tex != null && !defaultValue.Contains(tex))
+ defaultValue.Add(tex);
+ }
+ return defaultValue;
+ }
+
+ Color? Parse(string s, Color? defaultValue)
+ {
+ try { return ConfigNode.ParseColor(s); }
+ catch { return defaultValue; }
+ }
+
+ List Parse(string[] s, List defaultValue)
+ {
+ for (int i = 0; i < s.Length; i++)
+ {
+ Color? col = null;
+ col = Parse(s[i], col);
+ if (!defaultValue.Contains((Color)col))
+ defaultValue.Add((Color)col);
+ }
+
+ return defaultValue;
+ }
+
+ void ParseFolders(ConfigNode node)
+ {
+ if (node == null) return;
+
+ // Parse Texture Folders
+ pupilLeftTex = ParseFolders(node.GetValues("pupilLeftTex"), pupilLeftTex);
+ pupilRightTex = ParseFolders(node.GetValues("pupilRightTex"), pupilRightTex);
+ eyeballLeftTex = ParseFolders(node.GetValues("eyeballLeftTex"), eyeballLeftTex);
+ eyeballRightTex = ParseFolders(node.GetValues("eyeballRightTex"), eyeballRightTex);
+ upTeeth01Tex = ParseFolders(node.GetValues("upTeeth01Tex"), upTeeth01Tex);
+ upTeeth02Tex = ParseFolders(node.GetValues("upTeeth02Tex"), upTeeth02Tex);
+ tongueTex = ParseFolders(node.GetValues("tongueTex"), tongueTex);
+ headTex = ParseFolders(node.GetValues("headTex"), headTex);
+ hairTex = ParseFolders(node.GetValues("hairTex"), hairTex);
+
+ // Parse Normal Folders
+ pupilLeftNrm = ParseFolders(node.GetValues("pupilLeftNrm"), pupilLeftNrm);
+ pupilRightNrm = ParseFolders(node.GetValues("pupilRightNrm"), pupilRightNrm);
+ eyeballLeftNrm = ParseFolders(node.GetValues("eyeballLeftNrm"), eyeballLeftNrm);
+ eyeballRightNrm = ParseFolders(node.GetValues("eyeballRightNrm"), eyeballRightNrm);
+ upTeeth01Nrm = ParseFolders(node.GetValues("upTeeth01Nrm"), upTeeth01Nrm);
+ upTeeth02Nrm = ParseFolders(node.GetValues("upTeeth02Nrm"), upTeeth02Nrm);
+ tongueNrm = ParseFolders(node.GetValues("tongueNrm"), tongueNrm);
+ headNrm = ParseFolders(node.GetValues("headNrm"), headNrm);
+ hairNrm = ParseFolders(node.GetValues("hairNrm"), hairNrm);
+ }
+
+ List ParseFolders(string[] paths, List list)
+ {
+ for (int i = 0; i < paths?.Length; i++)
+ {
+ list.AddUniqueRange(ParseFolder(paths[i]));
+ }
+
+ return list;
+ }
+
+ List ParseFolder(string path)
+ {
+ if (!path.EndsWith("/")) path += "/";
+
+ Texture[] textures = Resources.FindObjectsOfTypeAll();
+ List list = new List();
+
+ if (Directory.Exists("GameData/" + path))
+ {
+ string[] files = Directory.GetFiles("GameData/" + path)?.Where(f => Path.GetExtension(f) == ".dds" || Path.GetExtension(f) == ".png")?.ToArray();
+
+ for (int i = 0; i < files?.Length; i++)
+ {
+ if (!string.IsNullOrEmpty(files[i]))
+ {
+ string name = path + Path.GetFileNameWithoutExtension(files[i]);
+ Texture texture = textures.FirstOrDefault(t => t?.name == name);
+
+ if (texture != null)
+ list.AddUnique(texture);
+ }
+ }
+ }
+
+ return list;
+ }
+
+
+ // Order DataBase
+ internal static void OrderDB()
+ {
+ Debug.Log("HeadInfo.OrderDB", "Total HeadInfo count = " + List?.Count);
+
+ DataBase.AddRange(List.Where(h => !string.IsNullOrEmpty(h?.name) && !string.IsNullOrEmpty(h?.collection)));
+ DataBase.AddRange(List.Where(h => !string.IsNullOrEmpty(h?.name) && string.IsNullOrEmpty(h?.collection)));
+ DataBase.AddRange(List.Where(h => string.IsNullOrEmpty(h?.name) && !string.IsNullOrEmpty(h?.collection)));
+ DataBase.AddRange(List.Where(h => h != null && string.IsNullOrEmpty(h?.name) && string.IsNullOrEmpty(h?.collection)));
+
+ Debug.Log("HeadInfo.OrderDB", "Valid HeadInfo count = " + DataBase?.Count);
+ }
+ }
+ }
+}
+
diff --git a/[Source]/SigmaReplacements/Heads/Properties/AssemblyInfo.cs b/[Source]/SigmaReplacements/Heads/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3695920
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+
+[assembly: AssemblyTitle("SigmaReplacementsHeads")]
+[assembly: AssemblyDescription("Sigma Replacements: Heads")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Sigma88")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Copyright (C) Sigma88 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: KSPAssembly("SigmaReplacementsHeads", 1, 0)]
+[assembly: AssemblyVersion("1.0.0")]
diff --git a/[Source]/SigmaReplacements/Heads/SettingsLoader.cs b/[Source]/SigmaReplacements/Heads/SettingsLoader.cs
new file mode 100644
index 0000000..826ee62
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/SettingsLoader.cs
@@ -0,0 +1,45 @@
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ class SettingsLoader : MonoBehaviour
+ {
+ void Start()
+ {
+ // Debug Spam
+ if (bool.TryParse(UserSettings.ConfigNode?.GetValue("debug"), out bool debug) && debug) Debug.debug = true;
+ }
+ }
+
+ namespace Heads
+ {
+ [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ class SettingsLoader : MonoBehaviour
+ {
+ void Start()
+ {
+ // User Settings
+ ConfigNode[] InfoNodes = UserSettings.ConfigNode.GetNodes("Kerbal");
+
+ for (int i = 0; i < InfoNodes?.Length; i++)
+ {
+ ConfigNode[] requirements = InfoNodes[i].GetNodes("Requirements");
+ ConfigNode head = InfoNodes[i].GetNode("Head");
+
+ if (requirements.Length == 0)
+ requirements = new[] { new ConfigNode() };
+
+ for (int j = 0; j < requirements.Length; j++)
+ {
+ HeadInfo.List.Add(new HeadInfo(requirements[j], head));
+ }
+ }
+
+ if (HeadInfo.List?.Count > 0)
+ HeadInfo.OrderDB();
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/SigmaReplacementsHeads.csproj b/[Source]/SigmaReplacements/Heads/SigmaReplacementsHeads.csproj
new file mode 100644
index 0000000..c25f19f
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/SigmaReplacementsHeads.csproj
@@ -0,0 +1,63 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}
+ Library
+ Properties
+ SigmaReplacements.Heads
+ SigmaReplacementsHeads
+ v3.5
+ 512
+
+
+
+ true
+ full
+ false
+ ..\..\Distribution\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\..\..\[References]\KerbalSpaceProgram\Assembly-CSharp.dll
+
+
+ False
+ ..\..\..\..\[References]\KerbalSpaceProgram\UnityEngine.dll
+
+
+
+
+
\ No newline at end of file
diff --git a/[Source]/SigmaReplacements/Heads/Triggers.cs b/[Source]/SigmaReplacements/Heads/Triggers.cs
new file mode 100644
index 0000000..2582b8b
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/Triggers.cs
@@ -0,0 +1,160 @@
+using UnityEngine;
+using System.Linq;
+using KSP.UI.Screens;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ [KSPAddon(KSPAddon.Startup.MainMenu, false)]
+ class MenuTriggers : MonoBehaviour
+ {
+ void Start()
+ {
+ Debug.Log("MenuTriggers", "Start");
+
+ Transform[] transforms = Resources.FindObjectsOfTypeAll();
+
+ int menu = 0;
+
+ for (int i = 0; i < transforms?.Length; i++)
+ {
+ Transform transform = transforms[i];
+
+ if (transform?.name == "Kerbals")
+ {
+ foreach (Transform child in transform)
+ {
+ if (child?.gameObject != null && child?.GetComponent() == null)
+ child.gameObject.AddComponent();
+
+ UIKerbalMenu kerbal = child.GetComponent();
+ kerbal.crewMember = UIKerbals.menuKerbals[menu];
+ menu++;
+
+ if (child?.gameObject != null && child?.GetComponent() == null)
+ child.gameObject.AddComponent();
+ }
+ }
+
+ if (transform?.name == "WernerVonKerman")
+ {
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+ }
+ }
+ }
+ }
+
+ [KSPAddon(KSPAddon.Startup.SpaceCentre, false)]
+ class KSCTriggers : MonoBehaviour
+ {
+ void Start()
+ {
+ Debug.Log("KSCTriggers", "Start");
+
+ Administration admin = Resources.FindObjectsOfTypeAll().FirstOrDefault();
+
+ if (admin?.gameObject != null && admin.GetComponent() == null)
+ {
+ admin.gameObject.AddComponent();
+ }
+
+
+ string[] names = new string[] { "Strategy_Mortimer", "Strategy_ScienceGuy", "Strategy_PRGuy", "Strategy_MechanicGuy" };
+
+ Transform[] transforms = Resources.FindObjectsOfTypeAll();
+
+ for (int i = 0; i < transforms?.Length; i++)
+ {
+ Transform transform = transforms[i];
+
+ if (names.Contains(transform?.name))
+ {
+ int index = names.IndexOf(transform?.name);
+
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+ }
+
+ if (transform?.name == "instructor_Gene")
+ {
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+
+ if (transform?.gameObject != null && transform?.GetComponent() == null)
+ transform.gameObject.AddComponent();
+ }
+ }
+ }
+ }
+
+ internal class AdminTrigger : MonoBehaviour
+ {
+ void Start()
+ {
+ Debug.Log("AdminTrigger", "Start");
+
+ UIKerbalStrategy[] strategies = GetComponentsInChildren();
+
+ for (int i = 0; i < strategies?.Length; i++)
+ {
+ if (strategies[i] != null)
+ strategies[i].Apply();
+ }
+ }
+ }
+
+ [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ class FlightTriggers : MonoBehaviour
+ {
+ void Start()
+ {
+ DontDestroyOnLoad(this);
+
+ Debug.Log("FlightTriggers", "Start");
+
+ GameEvents.onVesselLoaded.Add(OnVesselLoaded);
+ GameEvents.onVesselCreate.Add(OnVesselLoaded);
+ GameEvents.onCrewOnEva.Add(OnCrewOnEva);
+ }
+
+ void OnVesselLoaded(Vessel vessel)
+ {
+ Debug.Log("FlightTriggers.OnVesselLoaded", "Vessel = " + vessel);
+
+ KerbalEVA[] kerbalEVAs = vessel.GetComponentsInChildren(true);
+
+ for (int i = 0; i < kerbalEVAs?.Length; i++)
+ {
+ if (kerbalEVAs[i]?.GetComponent() == null)
+ kerbalEVAs[i].gameObject.AddComponent();
+ }
+
+ kerbalExpressionSystem[] kerbalIVAs = Resources.FindObjectsOfTypeAll();
+
+ for (int i = 0; i < kerbalIVAs?.Length; i++)
+ {
+ if (kerbalIVAs[i]?.GetComponent() == null)
+ kerbalIVAs[i].gameObject.AddComponent();
+ }
+ }
+
+ void OnCrewOnEva(GameEvents.FromToAction action)
+ {
+ Debug.Log("FlightTriggers.OnCrewOnEva", "Part = " + action.to);
+
+ KerbalEVA kerbalEVA = action.to.GetComponent();
+ if (kerbalEVA.GetComponent() == null)
+ kerbalEVA.gameObject.AddComponent();
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/UIKerbals.cs b/[Source]/SigmaReplacements/Heads/UIKerbals.cs
new file mode 100644
index 0000000..aaa0530
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/UIKerbals.cs
@@ -0,0 +1,135 @@
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ internal class UIKerbals : MonoBehaviour
+ {
+ // Main Menu
+ static CrewMember mun1 = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Bob Kerman", ProtoCrewMember.Gender.Male, "Scientist", true, false, 0.3f, 0.1f, 0);
+ static CrewMember orbit1 = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Bill Kerman", ProtoCrewMember.Gender.Male, "Engineer", true, false, 0.5f, 0.8f, 0);
+ static CrewMember orbit2 = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Bob Kerman", ProtoCrewMember.Gender.Male, "Scientist", true, false, 0.3f, 0.1f, 0);
+ static CrewMember orbit3 = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Jebediah Kerman", ProtoCrewMember.Gender.Male, "Pilot", true, true, 0.5f, 0.5f, 0);
+ static CrewMember orbit4 = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Valentina Kerman", ProtoCrewMember.Gender.Female, "Pilot", true, true, 0.55f, 0.4f, 0);
+ // Instructors
+ static CrewMember gene = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Gene Kerman", ProtoCrewMember.Gender.Male, "Instructor", false, false, 0.6f, 0.45f, 0);
+ static CrewMember werner = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Wernher von Kerman", ProtoCrewMember.Gender.Male, "Instructor", false, false, 0.25f, 0.25f, 0);
+ // Strategy
+ static CrewMember mort = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Mortimer Kerman", ProtoCrewMember.Gender.Male, "StockBroker", false, false, 0.65f, 0.35f, 0);
+ static CrewMember linus = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Linus Kerman", ProtoCrewMember.Gender.Male, "Researcher", false, false, 0.35f, 0.3f, 0);
+ static CrewMember walt = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Walt Kerman", ProtoCrewMember.Gender.Male, "Marketer", false, false, 0.45f, 0.9f, 0);
+ static CrewMember gus = new CrewMember(ProtoCrewMember.KerbalType.Crew, "Gus Kerman", ProtoCrewMember.Gender.Male, "Mechanic", false, false, 0.45f, 0.45f, 0);
+
+ internal static CrewMember[] menuKerbals = new[] { mun1, orbit1, orbit2, orbit3, orbit4 };
+ internal static CrewMember[] instructors = new[] { gene, werner };
+ internal static CrewMember[] strategy = new[] { mort, linus, walt, gus };
+ }
+
+ internal class UIKerbalMenu : MonoBehaviour
+ {
+ internal CrewMember crewMember;
+ }
+
+ internal class UIKerbalWerner : MonoBehaviour
+ {
+ internal CrewMember crewMember { get { return UIKerbals.instructors[1]; } }
+ }
+
+ internal class UIKerbalGene : MonoBehaviour
+ {
+ internal CrewMember crewMember { get { return UIKerbals.instructors[0]; } }
+ }
+
+ internal class UIKerbalStrategy : MonoBehaviour
+ {
+ static string[] names = new string[] { "Strategy_Mortimer(Clone)", "Strategy_ScienceGuy(Clone)", "Strategy_PRGuy(Clone)", "Strategy_MechanicGuy(Clone)" };
+
+ internal CrewMember crewMember
+ {
+ get
+ {
+ for (int i = 0; i < names.Length; i++)
+ {
+ if (gameObject?.name == names[i])
+ return UIKerbals.strategy[i];
+ }
+ return null;
+ }
+ }
+
+ internal void Apply()
+ {
+ CustomHead head = GetComponent();
+ if (head != null) head.Apply();
+ }
+ }
+
+ [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ internal class UIKerbalLoader : MonoBehaviour
+ {
+ void Awake()
+ {
+ Debug.Log("UIKerbalLoader", "Awake");
+
+ ConfigNode[] MenuKerbals = UserSettings.ConfigNode.GetNodes("MenuKerbal");
+
+ for (int i = 0; i < MenuKerbals?.Length; i++)
+ {
+ if (int.TryParse(MenuKerbals[i]?.GetValue("index"), out int index) && index < UIKerbals.menuKerbals?.Length)
+ {
+ UIKerbals.menuKerbals.Load(MenuKerbals[i], index);
+ }
+ }
+
+
+ ConfigNode[] Instructors = UserSettings.ConfigNode.GetNodes("Instructor");
+
+ for (int i = 0; i < Instructors?.Length; i++)
+ {
+ if (int.TryParse(Instructors[i]?.GetValue("index"), out int index) && index < UIKerbals.instructors?.Length)
+ {
+ UIKerbals.instructors.Load(Instructors[i], index);
+ }
+ }
+
+
+ ConfigNode[] StrategyKerbals = UserSettings.ConfigNode.GetNodes("StrategyKerbal");
+
+ for (int i = 0; i < StrategyKerbals?.Length; i++)
+ {
+ if (int.TryParse(StrategyKerbals[i]?.GetValue("index"), out int index) && index < UIKerbals.strategy?.Length)
+ {
+ UIKerbals.strategy.Load(StrategyKerbals[i], index);
+ }
+ }
+ }
+ }
+
+ internal class CrewMember : ProtoCrewMember
+ {
+ internal new string name = "";
+
+ internal CrewMember(KerbalType type, string name, Gender gender, string trait, bool veteran, bool isBadass, float courage, float stupidity, int experienceLevel) : base(type, name)
+ {
+ Debug.Log("CrewMember", "new CrewMember from stats");
+
+ this.type = type;
+ this.name = name;
+ this.gender = gender;
+ this.trait = trait;
+ this.veteran = veteran;
+ this.isBadass = isBadass;
+ this.courage = courage;
+ this.stupidity = stupidity;
+ this.experienceLevel = experienceLevel;
+ }
+
+ CrewMember(KerbalType type) : base(type) { }
+ CrewMember(ProtoCrewMember copyOf) : base(copyOf) { }
+ CrewMember(KerbalType type, string name) : base(type, name) { }
+ CrewMember(Game.Modes mode, ConfigNode node, KerbalType crewType = KerbalType.Crew) : base(mode, node, crewType) { }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/UserSettings.cs b/[Source]/SigmaReplacements/Heads/UserSettings.cs
new file mode 100644
index 0000000..72cf311
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/UserSettings.cs
@@ -0,0 +1,63 @@
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ [KSPAddon(KSPAddon.Startup.Instantly, true)]
+ internal class UserSettings : MonoBehaviour
+ {
+ internal static ConfigNode ConfigNode
+ {
+ get
+ {
+ return GameDatabase.Instance?.GetConfigs(nodeName)?.FirstOrDefault(n => n.url == (folder.Substring(9) + file + "/" + nodeName))?.config;
+ }
+ }
+
+ static string folder = "GameData/Sigma/Replacements/";
+ static string file = "Settings";
+ internal static string nodeName = "SigmaReplacements";
+
+ void Awake()
+ {
+ string path = Assembly.GetExecutingAssembly().Location.Replace('\\', '/');
+ while (path.Substring(1).Contains("GameData/"))
+ path = path.Substring(1 + path.Substring(1).IndexOf("GameData/"));
+
+ if (!Directory.Exists(folder))
+ {
+ UnityEngine.Debug.Log(Debug.Tag + " WARNING: Missing folder => " + folder);
+ return;
+ }
+
+ if (!File.Exists(folder + file + ".cfg"))
+ {
+ UnityEngine.Debug.Log(Debug.Tag + " WARNING: Missing file => " + folder + file + ".cfg");
+
+ File.WriteAllLines(folder + file + ".cfg", new[] { nodeName + " {}" });
+ return;
+ }
+
+ if (ConfigNode.Load(folder + file + ".cfg")?.HasNode(nodeName) != true)
+ {
+ UnityEngine.Debug.Log(Debug.Tag + " WARNING: Missing node => " + folder + file + "/" + nodeName);
+
+ File.AppendAllText(folder + file + ".cfg", "\r\n" + nodeName + " {}");
+ }
+ }
+
+ void Start()
+ {
+ var configs = GameDatabase.Instance.GetConfigs(nodeName);
+
+ for (int i = 0; i < configs?.Length; i++)
+ {
+ if (configs[i].url != (folder.Substring(9) + file + "/" + nodeName))
+ configs[i].parent.configs.Remove(configs[i]);
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/Heads/Version.cs b/[Source]/SigmaReplacements/Heads/Version.cs
new file mode 100644
index 0000000..2c7b6f2
--- /dev/null
+++ b/[Source]/SigmaReplacements/Heads/Version.cs
@@ -0,0 +1,19 @@
+using UnityEngine;
+
+
+namespace SigmaReplacements
+{
+ namespace Heads
+ {
+ [KSPAddon(KSPAddon.Startup.Instantly, true)]
+ public class Version : MonoBehaviour
+ {
+ public static readonly System.Version number = new System.Version("0.1.0");
+
+ void Awake()
+ {
+ UnityEngine.Debug.Log("[SigmaLog] Version Check: Sigma Replacements: Heads v" + number);
+ }
+ }
+ }
+}
diff --git a/[Source]/SigmaReplacements/SigmaReplacements.sln b/[Source]/SigmaReplacements/SigmaReplacements.sln
new file mode 100644
index 0000000..51a1979
--- /dev/null
+++ b/[Source]/SigmaReplacements/SigmaReplacements.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.16
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SigmaReplacementsHeads", "Heads\SigmaReplacementsHeads.csproj", "{D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SigmaReplacementsSuits", "Suits\SigmaReplacementsSuits.csproj", "{B3769F47-5A16-43C9-995F-1B3B15BE97CC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SigmaReplacementsTextures", "Textures\SigmaReplacementsTextures.csproj", "{85E7DC1E-15EA-4C98-B6D3-52CB27BB9526}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6D14E8B-1ED9-43D1-A9D2-4F3A4A6A6F4D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B3769F47-5A16-43C9-995F-1B3B15BE97CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B3769F47-5A16-43C9-995F-1B3B15BE97CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B3769F47-5A16-43C9-995F-1B3B15BE97CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B3769F47-5A16-43C9-995F-1B3B15BE97CC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85E7DC1E-15EA-4C98-B6D3-52CB27BB9526}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85E7DC1E-15EA-4C98-B6D3-52CB27BB9526}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85E7DC1E-15EA-4C98-B6D3-52CB27BB9526}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85E7DC1E-15EA-4C98-B6D3-52CB27BB9526}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E50D5E74-B8EE-48C9-9D22-5FCF86BB4E44}
+ EndGlobalSection
+EndGlobal