diff --git a/EdBPrepareCarefully.csproj b/EdBPrepareCarefully.csproj
index bbd81f4..d07e32e 100644
--- a/EdBPrepareCarefully.csproj
+++ b/EdBPrepareCarefully.csproj
@@ -34,7 +34,8 @@
- Libraries\Harmony\2.0\0Harmony.dll
+ False
+ Libraries\Harmony\2.2.2\0Harmony.dll
False
@@ -58,6 +59,7 @@
+
@@ -80,13 +82,13 @@
+
-
@@ -119,7 +121,6 @@
-
@@ -219,7 +220,11 @@
+
+
+
+
@@ -227,7 +232,6 @@
-
@@ -283,4 +287,8 @@
+
+ cd $(SolutionDir)
+deploy.bat
+
\ No newline at end of file
diff --git a/EdBPrepareCarefully.sln b/EdBPrepareCarefully.sln
index 17aa399..b740ae9 100644
--- a/EdBPrepareCarefully.sln
+++ b/EdBPrepareCarefully.sln
@@ -1,6 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33103.184
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EdBPrepareCarefully", "EdBPrepareCarefully.csproj", "{86C9833E-894B-4633-ACFA-EFE4157BBBE6}"
EndProject
Global
@@ -14,12 +16,18 @@ Global
{86C9833E-894B-4633-ACFA-EFE4157BBBE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86C9833E-894B-4633-ACFA-EFE4157BBBE6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {18BEA049-3BB9-4853-9F6A-E122019E4EB3}
+ EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = None
$1.ResourceNamePolicy = FileFormatDefault
- $0.TextStylePolicy = $2
+ $0.TextStylePolicy = $5
$2.FileWidth = 120
$2.inheritsSet = VisualStudio
$2.inheritsScope = text/plain
@@ -51,13 +59,11 @@ Global
$3.NewLinesForBracesInTypes = False
$3.NewLinesForBracesInMethods = False
$3.SpaceAfterCast = True
- $0.TextStylePolicy = $4
$4.FileWidth = 120
$4.TabsToSpaces = False
$4.inheritsSet = null
$4.inheritsScope = text/plain
$4.scope = application/xml
- $0.TextStylePolicy = $5
$5.inheritsSet = null
$5.scope = text/x-csharp
$0.XmlFormattingPolicy = $6
@@ -69,7 +75,7 @@ Global
$7.IncludeInNewFiles = True
$0.NameConventionPolicy = $8
$8.Rules = $9
- $9.NamingRule = $10
+ $9.NamingRule = $29
$10.Name = Type Parameters
$10.AffectedEntity = TypeParameter
$10.VisibilityMask = VisibilityMask
@@ -80,14 +86,12 @@ Global
$32.String = T
$10.RequiredSuffixes = $33
$33.String = Exception
- $9.NamingRule = $11
$11.Name = Types
$11.AffectedEntity = Class, Struct, Enum, Delegate
$11.VisibilityMask = Public
$11.NamingStyle = PascalCase
$11.IncludeInstanceMembers = True
$11.IncludeStaticEntities = True
- $9.NamingRule = $12
$12.Name = Interfaces
$12.RequiredPrefixes = $13
$13.String = I
@@ -96,7 +100,6 @@ Global
$12.NamingStyle = PascalCase
$12.IncludeInstanceMembers = True
$12.IncludeStaticEntities = True
- $9.NamingRule = $14
$14.Name = Attributes
$14.RequiredSuffixes = $15
$15.String = Attribute
@@ -105,7 +108,6 @@ Global
$14.NamingStyle = PascalCase
$14.IncludeInstanceMembers = True
$14.IncludeStaticEntities = True
- $9.NamingRule = $16
$16.Name = Event Arguments
$16.RequiredSuffixes = $17
$17.String = EventArgs
@@ -114,7 +116,6 @@ Global
$16.NamingStyle = PascalCase
$16.IncludeInstanceMembers = True
$16.IncludeStaticEntities = True
- $9.NamingRule = $18
$18.Name = Exceptions
$18.RequiredSuffixes = $19
$19.String = Exception
@@ -123,70 +124,60 @@ Global
$18.NamingStyle = PascalCase
$18.IncludeInstanceMembers = True
$18.IncludeStaticEntities = True
- $9.NamingRule = $20
$20.Name = Methods
$20.AffectedEntity = Methods
$20.VisibilityMask = Protected, Public
$20.NamingStyle = PascalCase
$20.IncludeInstanceMembers = True
$20.IncludeStaticEntities = True
- $9.NamingRule = $21
$21.Name = Static Readonly Fields
$21.AffectedEntity = ReadonlyField
$21.VisibilityMask = Protected, Public
$21.NamingStyle = PascalCase
$21.IncludeInstanceMembers = False
$21.IncludeStaticEntities = True
- $9.NamingRule = $22
$22.Name = Fields
$22.AffectedEntity = Field
$22.VisibilityMask = Protected, Public
$22.NamingStyle = PascalCase
$22.IncludeInstanceMembers = True
$22.IncludeStaticEntities = True
- $9.NamingRule = $23
$23.Name = ReadOnly Fields
$23.AffectedEntity = ReadonlyField
$23.VisibilityMask = Protected, Public
$23.NamingStyle = PascalCase
$23.IncludeInstanceMembers = True
$23.IncludeStaticEntities = False
- $9.NamingRule = $24
$24.Name = Constant Fields
$24.AffectedEntity = ConstantField
$24.VisibilityMask = Protected, Public
$24.NamingStyle = PascalCase
$24.IncludeInstanceMembers = True
$24.IncludeStaticEntities = True
- $9.NamingRule = $25
$25.Name = Properties
$25.AffectedEntity = Property
$25.VisibilityMask = Protected, Public
$25.NamingStyle = PascalCase
$25.IncludeInstanceMembers = True
$25.IncludeStaticEntities = True
- $9.NamingRule = $26
$26.Name = Events
$26.AffectedEntity = Event
$26.VisibilityMask = Protected, Public
$26.NamingStyle = PascalCase
$26.IncludeInstanceMembers = True
$26.IncludeStaticEntities = True
- $9.NamingRule = $27
$27.Name = Enum Members
$27.AffectedEntity = EnumMember
$27.VisibilityMask = VisibilityMask
$27.NamingStyle = PascalCase
$27.IncludeInstanceMembers = True
$27.IncludeStaticEntities = True
- $9.NamingRule = $28
$28.Name = Parameters
$28.AffectedEntity = Parameter
$28.VisibilityMask = VisibilityMask
$28.NamingStyle = CamelCase
$28.IncludeInstanceMembers = True
$28.IncludeStaticEntities = True
- $9.NamingRule = $29
$29.Name = Type Parameters
$29.RequiredPrefixes = $30
$30.String = T
diff --git a/Libraries/README.md b/Libraries/README.md
index 9e8af8f..a9f121e 100644
--- a/Libraries/README.md
+++ b/Libraries/README.md
@@ -10,6 +10,6 @@ The solution has dependencies on the following RimWorld DLLs:
Copy those dependencies from the RimWorld game directory into the "Libraries" directory. Be sure to make _copies_ of the originals--don't accidentally move/delete them from the original game directory.
The solution also has a dependency on the following third-party DLL:
-- 0Harmony.dll (version 2.0.2)
+- 0Harmony.dll (version 2.2.2)
-The Harmony DLL is available from https://github.com/pardeike/Harmony/releases/tag/v2.0.2.0 and should be placed in the "Libraries/Harmony/2.0" directory. Be sure to use the "Release/net472" version.
+The Harmony DLL is available from https://github.com/pardeike/Harmony/releases/tag/v2.2.2.0 and should be placed in the "Libraries/Harmony/2.2.2" directory. Be sure to use the "net472" version.
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index aa7f086..7bc2d62 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -6,7 +6,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EdB Prepare Carefully Mod")]
-[assembly: AssemblyCopyright("Copyright © 2014-2021")]
+[assembly: AssemblyCopyright("Copyright © 2014-2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -14,4 +14,4 @@
[assembly: AssemblyVersion("1.1.1")]
// Increment for each new release
-[assembly: AssemblyFileVersion("1.3.12")]
+[assembly: AssemblyFileVersion("1.4.1")]
diff --git a/Resources/About/About.xml b/Resources/About/About.xml
index 3fca111..78711f5 100644
--- a/Resources/About/About.xml
+++ b/Resources/About/About.xml
@@ -8,12 +8,13 @@
1.1
1.2
1.3
+ 1.4
Customize your colonists, choose your gear and prepare carefully for your crash landing!
If you get a set of starting colonists that you like, save them as a preset so that you can start your game the same way next time.
-[Version 1.3.12]
+[Version 1.4.1]
net.pardeike.rimworld.mod.harmony
diff --git a/Resources/About/Manifest.xml b/Resources/About/Manifest.xml
index f297840..1769584 100644
--- a/Resources/About/Manifest.xml
+++ b/Resources/About/Manifest.xml
@@ -1,7 +1,7 @@
EdB.PrepareCarefully
- 1.3.12
+ 1.4.1
false
https://github.com/edbmods/EdBPrepareCarefully/raw/master/Resources/About/Manifest.xml
https://github.com/edbmods/EdBPrepareCarefully/releases/latest
diff --git a/Resources/CHANGELOG.txt b/Resources/CHANGELOG.txt
index ae321df..be07bcb 100644
--- a/Resources/CHANGELOG.txt
+++ b/Resources/CHANGELOG.txt
@@ -1,3 +1,14 @@
+ _____________________________________________________________________________
+
+ Version 1.4.1
+ _____________________________________________________________________________
+
+ - Compatibility for 1.4 and Biotech
+ - Added Xenotype panel
+ - Added "Days" field to age panel
+ - Added dropdown options to the randomize panel
+ - Added starting pawn possessions to the equipment list
+
_____________________________________________________________________________
Version 1.3.12
@@ -14,7 +25,7 @@
_____________________________________________________________________________
- Fixed issue with missing relationships when loading presets.
- - Fixed apparel for alien race mods where the alien race uses restricted
+ - Fixed apparel for alien race mods where the alien race uses restricted
apparel.
_____________________________________________________________________________
diff --git a/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml b/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
index 9020b46..7a5f01d 100644
--- a/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
+++ b/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
@@ -1,5 +1,15 @@
+
+
+
+
+
+
+
+
+
+
@@ -281,6 +291,7 @@ Before reporting an error, please try to figure out which mod may be causing the
Apparel: {0}
{0}: {1}
Implants: {0}
+ Disable Point Limits
You've spent too many points.
Points Remaining: {0}
The starting colonists and resources that were randomly generated for this scenario were worth {0} points.
@@ -294,7 +305,12 @@ Disable point limits to prepare your starting colonists with no limitations.
Prepare Carefully
No abilities
-
+
+ Age
+ Biological
+ Chronological
+ Years
+ Days
Biological Age
Chronological Age
@@ -342,6 +358,11 @@ You can play the game with your colonists as they are, but you will be asked to
({0})
Select From a Faction Template
+ {0}
+Click the randomize button to generate a colonist within this developmental stage's age range
+ {0}
+Click the randomize button to generate a colonist with this xenotype
+
Other Relationships
Parent, Child and Sibling Relationships
diff --git a/Resources/LoadFolders.xml b/Resources/LoadFolders.xml
index 1800c6e..4bb27c6 100644
--- a/Resources/LoadFolders.xml
+++ b/Resources/LoadFolders.xml
@@ -11,4 +11,8 @@
Common
1.3
+
+ Common
+ 1.4
+
\ No newline at end of file
diff --git a/Source/AgeModifier.cs b/Source/AgeModifier.cs
new file mode 100644
index 0000000..8e5447c
--- /dev/null
+++ b/Source/AgeModifier.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace EdB.PrepareCarefully {
+ public class AgeModifier {
+ public static long TicksPerYear = 3600000L;
+ public static long TicksPerDay = 60000L;
+ public static long DaysPerYear = 60L;
+ public static long TicksFromYearsAndDays(int years, int days) {
+ return ((long)years * TicksPerYear) + ((long)days * TicksPerDay);
+ }
+
+ BackstoryDef newbornBackstory;
+ BackstoryDef childBackstory;
+ public void ModifyBiologicalAge(CustomPawn pawn, long ticks) {
+ if (pawn == null) {
+ return;
+ }
+
+ int previousLifeStageIndex = pawn.Pawn.ageTracker.CurLifeStageIndex;
+ LifeStageDef previousLifeStage = pawn.Pawn.ageTracker.CurLifeStage;
+ LifeStageAge previousLifeStageAge = pawn.Pawn.ageTracker.CurLifeStageRace;
+
+ bool wasNewborn = IsNewborn(pawn);
+ bool wasChild = IsChild(pawn);
+ bool hadChildhoodBackstory = HasChildhoodBackstory(pawn);
+ bool hadAdulthoodBackstory = HasAdulthoodBackstory(pawn);
+
+ pawn.Pawn.ageTracker.AgeBiologicalTicks = ticks;
+
+ bool hasChildhoodBackstory = HasChildhoodBackstory(pawn);
+ bool hasAdulthoodBackstory = HasAdulthoodBackstory(pawn);
+ bool isNewborn = IsNewborn(pawn);
+ bool isChild = IsChild(pawn);
+
+ if (hasAdulthoodBackstory && !hadAdulthoodBackstory) {
+ pawn.Pawn.story.Adulthood = pawn.LastSelectedAdulthoodBackstory;
+ pawn.ResetBackstories();
+ }
+ else if (!hasAdulthoodBackstory && hadAdulthoodBackstory) {
+ pawn.Pawn.story.Adulthood = null;
+ pawn.ResetBackstories();
+ }
+
+ if (isNewborn && pawn.Pawn.story.Childhood != NewbornBackstory) {
+ pawn.Pawn.story.Childhood = NewbornBackstory;
+ pawn.ResetBackstories();
+ }
+ else if (isChild && pawn.Pawn.story.Childhood != ChildBackstory) {
+ pawn.Pawn.story.Childhood = ChildBackstory;
+ pawn.ResetBackstories();
+ }
+
+ pawn.Pawn.ClearCachedLifeStage();
+ pawn.Pawn.ClearCachedHealth();
+ pawn.MarkPortraitAsDirty();
+
+ int newLifeStageIndex = pawn.Pawn.ageTracker.CurLifeStageIndex;
+ LifeStageDef newLifeStage = pawn.Pawn.ageTracker.CurLifeStage;
+ LifeStageAge newLifeStageAge = pawn.Pawn.ageTracker.CurLifeStageRace;
+
+ if (newLifeStage != previousLifeStage) {
+ Logger.Debug("Pawn life stage changes from " + previousLifeStage.defName + " to " + newLifeStage.defName);
+ Logger.Debug("Development stage was " + previousLifeStage.developmentalStage + " and now is " + newLifeStage.developmentalStage);
+ }
+ }
+
+ public void ModifyChronologicalAge(CustomPawn pawn, long ticks) {
+ if (pawn == null) {
+ return;
+ }
+ pawn.Pawn.ageTracker.AgeChronologicalTicks = ticks;
+ }
+
+ public bool IsNewborn(CustomPawn pawn) {
+ DevelopmentalStage? d = pawn.Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ var value = d.HasValue ? d.Value.Baby() : false;
+ //Logger.Debug("IsNewborn = " + value);
+ return value;
+ }
+ public bool IsChild(CustomPawn pawn) {
+ DevelopmentalStage? d = pawn.Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ var value = d.HasValue ? d.Value.Child() : false;
+ //Logger.Debug("IsChild = " + value);
+ return value;
+ }
+ public bool IsAdult(CustomPawn pawn) {
+ DevelopmentalStage? d = pawn.Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ return d.HasValue ? d.Value.Adult() : false;
+ }
+
+ public bool HasChildhoodBackstory(CustomPawn pawn) {
+ return !IsNewborn(pawn) && !IsChild(pawn);
+ }
+ public bool HasAdulthoodBackstory(CustomPawn pawn) {
+ return IsAdult(pawn);
+ }
+
+ public BackstoryDef NewbornBackstory {
+ get {
+ if (newbornBackstory== null) {
+ newbornBackstory = DefDatabase.AllDefs.Where(b => b.spawnCategories != null && b.spawnCategories.Contains("Newborn")).FirstOrDefault();
+ }
+ return newbornBackstory;
+ }
+ }
+ public BackstoryDef ChildBackstory {
+ get {
+ if (childBackstory == null) {
+ childBackstory = DefDatabase.AllDefs.Where(b => b.spawnCategories != null && b.spawnCategories.Contains("Child")).FirstOrDefault();
+ }
+ return childBackstory;
+ }
+ }
+ }
+
+
+}
diff --git a/Source/AlienRace.cs b/Source/AlienRace.cs
index 3ae733b..e8df967 100644
--- a/Source/AlienRace.cs
+++ b/Source/AlienRace.cs
@@ -37,10 +37,7 @@ public List HairColors {
public List BodyTypes {
get; set;
}
- public List CrownTypes {
- get; set;
- }
- public bool GenderSpecificHeads {
+ public List HeadTypes {
get; set;
}
public string GraphicsPathForHeads {
diff --git a/Source/Controller.cs b/Source/Controller.cs
index 09eda35..ba07de5 100644
--- a/Source/Controller.cs
+++ b/Source/Controller.cs
@@ -149,6 +149,7 @@ protected void PrepareColonists() {
}
customPawn.Pawn.workSettings.EnableAndInitialize();
colonists.Add(customPawn.Pawn);
+ Find.GameInitData.startingPossessions[customPawn.Pawn] = new List();
}
}
Find.GameInitData.startingPawnCount = colonists.Count;
@@ -158,6 +159,7 @@ protected void PrepareColonists() {
protected void PrepareWorldPawns() {
foreach (var customPawn in state.Pawns) {
if (customPawn.Type == CustomPawnType.World) {
+ Find.GameInitData.startingPossessions[customPawn.Pawn] = new List();
AddPawnToWorld(customPawn);
}
}
@@ -183,6 +185,7 @@ protected void PrepareRelatedPawns() {
}
protected void AddPawnToWorld(CustomPawn pawn) {
+
// Don't add colonists to the world
if (pawn.Type == CustomPawnType.Colonist) {
return;
@@ -254,6 +257,7 @@ protected void AddPawnToWorld(CustomPawn pawn) {
else {
Find.GameInitData.startingAndOptionalPawns.Add(pawn.Pawn);
}
+
}
protected void MakePawnIntoFactionLeader(CustomPawn pawn) {
diff --git a/Source/ControllerPawns.cs b/Source/ControllerPawns.cs
index f81f580..d7cdbbf 100644
--- a/Source/ControllerPawns.cs
+++ b/Source/ControllerPawns.cs
@@ -19,6 +19,7 @@ public class ControllerPawns {
private State state;
private Randomizer randomizer = new Randomizer();
private ProviderAgeLimits ProviderAgeLimits = PrepareCarefully.Instance.Providers.AgeLimits;
+ private AgeModifier ageModifier = new AgeModifier();
public ControllerPawns(State state) {
this.state = state;
}
@@ -49,13 +50,75 @@ public void CheckPawnCapabilities() {
public void RandomizeAll() {
// Create the pawn.
- Pawn pawn = randomizer.GenerateKindOfPawn(state.CurrentPawn.Pawn.kindDef);
+ Pawn pawn = ModsConfig.BiotechActive ? CreateRandomizedPawnForBiotech() : randomizer.GenerateKindOfPawn(state.CurrentPawn.Pawn.kindDef);
if (pawn.Faction != Faction.OfPlayer) {
pawn.SetFactionDirect(Faction.OfPlayer);
}
+ bool randomizeAny = state.CurrentPawn.RandomizeAnyNonArchite;
state.CurrentPawn.InitializeWithPawn(pawn);
state.CurrentPawn.GenerateId();
PawnReplaced(state.CurrentPawn);
+ if (randomizeAny) {
+ state.CurrentPawn.RandomizeAnyNonArchite = true;
+ state.CurrentPawn.RandomizeCustomXenotype = null;
+ state.CurrentPawn.RandomizeXenotype = null;
+ }
+ }
+
+ public Pawn CreateRandomizedPawnForBiotech() {
+ var wrapper = new PawnGenerationRequestWrapper() {
+ Faction = Find.FactionManager.OfPlayer,
+ KindDef = state.CurrentPawn.Pawn.kindDef
+ };
+ Ideo ideo = Find.FactionManager.OfPlayer.ideos.GetRandomIdeoForNewPawn();
+ if (ideo != null) {
+ wrapper.FixedIdeology = ideo;
+ }
+ if (state.CurrentPawn.RandomizeDevelopmentalStage != DevelopmentalStage.Adult) {
+ wrapper.DevelopmentalStage = state.CurrentPawn.RandomizeDevelopmentalStage;
+ }
+ if (state.CurrentPawn.RandomizeXenotype != null) {
+ wrapper.ForcedXenotype = state.CurrentPawn.RandomizeXenotype;
+ }
+ else if (state.CurrentPawn.RandomizeCustomXenotype != null) {
+ wrapper.ForcedCustomXenotype = state.CurrentPawn.RandomizeCustomXenotype;
+ }
+ else {
+ wrapper.AllowedXenotypes = DefDatabase.AllDefs.Where((XenotypeDef x) => !x.Archite && x != XenotypeDefOf.Baseliner).ToList();
+ wrapper.ForceBaselinerChance = 0.5f;
+ }
+ Pawn pawn = randomizer.AttemptToGeneratePawn(wrapper.Request);
+
+ // Fix bad head type for Alien races
+ if (pawn.def.defName != "Human") {
+ var provider = PrepareCarefully.Instance.Providers.HeadTypes;
+ var headTypes = provider.GetHeadTypes(pawn);
+ if (headTypes.FirstOrDefault() != null && !headTypes.Contains(pawn.story.headType)) {
+ var replacement = provider.GetHeadTypes(pawn).First();
+ Logger.Warning("Swapped out missing head type (" + pawn.story.headType?.defName + ") with first valid head type (" + replacement?.defName + ") for alien race (" + pawn.def.defName + ")");
+ pawn.story.headType = replacement;
+ }
+ }
+
+ // Fix bad body type for Alien races
+ if (pawn.def.defName != "Human") {
+ var provider = PrepareCarefully.Instance.Providers.BodyTypes;
+ var bodyTypes = provider.GetBodyTypesForPawn(pawn);
+ if (!bodyTypes.Contains(pawn.story.bodyType)) {
+ Logger.Warning("Alien race (" + pawn.def.defName + ") does not include the generated body type (" + pawn.story.bodyType?.defName + ")");
+ if (bodyTypes.FirstOrDefault() != null) {
+ var replacement = provider.GetBodyTypesForPawn(pawn).First();
+ Logger.Warning("Swapped out missing body type (" + pawn.story.bodyType?.defName + ") with first valid body type (" + replacement?.defName + ") for alien race (" + pawn.def.defName + ")");
+ pawn.story.bodyType = replacement;
+ }
+ else {
+ Logger.Warning("No body types available in the alien race (" + pawn.def.defName + ") definition");
+ }
+ }
+
+ }
+
+ return pawn;
}
// Name-related actions.
@@ -82,7 +145,7 @@ public void RandomizeName() {
}
// Backstory-related actions.
- public void UpdateBackstory(BackstorySlot slot, Backstory backstory) {
+ public void UpdateBackstory(BackstorySlot slot, BackstoryDef backstory) {
if (slot == BackstorySlot.Childhood) {
state.CurrentPawn.Childhood = backstory;
}
@@ -141,7 +204,7 @@ public void RemoveTrait(Trait trait) {
}
public void RandomizeTraits() {
- Pawn pawn = randomizer.GenerateSameKindOfPawn(state.CurrentPawn);
+ Pawn pawn = randomizer.GeneratePawnAsCloseToAsPossible(state.CurrentPawn.Pawn);
List traits = pawn.story.traits.allTraits;
state.CurrentPawn.ClearTraits();
foreach (var trait in traits) {
@@ -166,31 +229,41 @@ public void SetAbilities(IEnumerable abilities) {
}
// Age-related actions.
- public void UpdateBiologicalAge(int age) {
+ public void UpdateBiologicalAge(int? ageYears, int? ageDays) {
+ int years = ageYears ?? state.CurrentPawn.BiologicalAgeInYears;
+ int days = ageDays ?? (int)(state.CurrentPawn.BiologicalAgeInDays % AgeModifier.DaysPerYear);
int min = ProviderAgeLimits.MinAgeForPawn(state.CurrentPawn.Pawn);
int max = ProviderAgeLimits.MaxAgeForPawn(state.CurrentPawn.Pawn);
- if (age < min) {
- age = min;
+ if (years < min) {
+ years = min;
+ days = 0;
}
- else if (age > max || age > state.CurrentPawn.ChronologicalAge) {
- if (age > max) {
- age = max;
- }
- else {
- age = state.CurrentPawn.ChronologicalAge;
- }
+ else if (years > max) {
+ years = max;
+ days = 59;
+ }
+ long ticks = AgeModifier.TicksFromYearsAndDays(years, days);
+ ticks += state.CurrentPawn.BiologicalAgeInTicks % AgeModifier.TicksPerDay;
+ ageModifier.ModifyBiologicalAge(state.CurrentPawn, ticks);
+ if (ticks > state.CurrentPawn.ChronologicalAgeInTicks) {
+ ageModifier.ModifyChronologicalAge(state.CurrentPawn, ticks);
}
- state.CurrentPawn.BiologicalAge = age;
}
- public void UpdateChronologicalAge(int age) {
- if (age < state.CurrentPawn.BiologicalAge) {
- age = state.CurrentPawn.BiologicalAge;
+ public void UpdateChronologicalAge(int? ageYears, int? ageDays) {
+ int years = ageYears ?? state.CurrentPawn.ChronologicalAgeInYears;
+ int days = ageDays ?? (int)(state.CurrentPawn.ChronologicalAgeInDays % AgeModifier.DaysPerYear);
+ int min = ProviderAgeLimits.MinAgeForPawn(state.CurrentPawn.Pawn);
+ if (years < min) {
+ years = min;
+ days = 0;
}
- if (age > Constraints.AgeChronologicalMax) {
- age = Constraints.AgeChronologicalMax;
+ long ticks = AgeModifier.TicksFromYearsAndDays(years, days);
+ ticks += state.CurrentPawn.ChronologicalAgeInTicks % AgeModifier.TicksPerDay;
+ ageModifier.ModifyChronologicalAge(state.CurrentPawn, ticks);
+ if (ticks < state.CurrentPawn.BiologicalAgeInTicks) {
+ ageModifier.ModifyBiologicalAge(state.CurrentPawn, ticks);
}
- state.CurrentPawn.ChronologicalAge = age;
}
// Appearance-related actions.
@@ -312,25 +385,33 @@ public void SaveCharacter(CustomPawn pawn, string filename) {
ColonistSaver.SaveToFile(pawn, filename);
state.AddMessage("SavedAs".Translate(filename));
}
- public void AddFactionPawn(PawnKindDef kindDef, bool startingPawn) {
+ public void AddFactionPawn(PawnKindOption option, bool startingPawn) {
Pawn pawn = null;
try {
- //Logger.Debug("Adding new pawn with kindDef = " + kindDef.defName);
+ //Logger.Debug("Adding new pawn " + option);
var wrapper = new PawnGenerationRequestWrapper() {
Faction = Find.World.factionManager.OfPlayer,
- KindDef = kindDef,
+ KindDef = option.KindDef,
Context = PawnGenerationContext.NonPlayer,
- WorldPawnFactionDoesntMatter = true
+ WorldPawnFactionDoesntMatter = true,
};
Ideo ideo = Find.FactionManager.OfPlayer?.ideos?.GetRandomIdeoForNewPawn();
-
+ //Logger.Debug("Pawn kind xenotype set: " + option?.KindDef?.xenotypeSet?.ToStringSafe());
+ //Logger.Debug("Faction xenotype set: " + option?.FactionDef?.xenotypeSet?.ToStringSafe());
+ XenotypeSet setToGenerateWith = option?.FactionDef?.xenotypeSet;
+ if (setToGenerateWith == null) {
+ setToGenerateWith = option?.KindDef?.xenotypeSet;
+ }
+ if (setToGenerateWith != null) {
+ wrapper.ForcedXenotype = this.randomizer.RandomXenotypeFromSet(setToGenerateWith);
+ }
if (ideo != null) {
wrapper.FixedIdeology = ideo;
}
pawn = randomizer.GeneratePawn(wrapper.Request);
}
catch (Exception e) {
- Logger.Warning("Failed to create faction pawn of kind " + kindDef.defName, e);
+ Logger.Warning("Failed to create faction pawn: " + option, e);
if (pawn != null) {
pawn.Destroy();
}
@@ -351,8 +432,11 @@ public void AddFactionPawn(PawnKindDef kindDef, bool startingPawn) {
//}
CustomPawn customPawn = new CustomPawn(pawn);
- customPawn.OriginalKindDef = kindDef;
- FactionDef factionDef = kindDef.defaultFactionType;
+ customPawn.OriginalKindDef = option.KindDef;
+ FactionDef factionDef = option.FactionDef;
+ if (factionDef == null) {
+ factionDef = option?.KindDef?.defaultFactionType;
+ }
customPawn.OriginalFactionDef = factionDef;
if (pawn.Faction != Faction.OfPlayer) {
pawn.SetFaction(Faction.OfPlayer);
diff --git a/Source/CustomHeadType.cs b/Source/CustomHeadType.cs
deleted file mode 100644
index 85ef782..0000000
--- a/Source/CustomHeadType.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using RimWorld;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using UnityEngine;
-using Verse;
-using Verse.Sound;
-
-namespace EdB.PrepareCarefully {
- public class CustomHeadType {
- private CrownType crownType;
- private string graphicPath;
- private string alternateGraphicPath;
- public string AlienCrownType {
- get; set;
- }
- private Gender? gender;
- public CrownType CrownType {
- get {
- return crownType;
- }
- set {
- crownType = value;
- }
- }
- public string GraphicPath {
- get {
- return graphicPath;
- }
- set {
- graphicPath = value;
- }
- }
- public string AlternateGraphicPath {
- get {
- return alternateGraphicPath;
- }
- set {
- alternateGraphicPath = value;
- }
- }
- public Gender? Gender {
- get {
- return gender;
- }
- set {
- gender = value;
- }
- }
- public string Label {
- get; set;
- }
- public CustomHeadType() {
-
- }
- protected static string GetHeadLabel(string path) {
- try {
- string[] pathValues = path.Split('/');
- string crownType = pathValues[pathValues.Length - 1];
- string[] values = crownType.Split('_');
- return values[values.Count() - 2] + ", " + values[values.Count() - 1];
- }
- catch (Exception) {
- Logger.Warning("Could not determine head type label from graphics path: " + path);
- return "EdB.PC.Common.Default".Translate();
- }
- }
- public override string ToString() {
- return "{ label = \"" + Label + "\", graphicsPath = \"" + graphicPath + "\", crownType = " + crownType + "\", AlienCrownType = " + AlienCrownType + ", gender = " + gender + "}";
- }
- }
-}
diff --git a/Source/CustomPawn.cs b/Source/CustomPawn.cs
index 300f553..da44677 100644
--- a/Source/CustomPawn.cs
+++ b/Source/CustomPawn.cs
@@ -42,12 +42,13 @@ public class CustomPawn {
// Keep track of the most recently selected adulthood option so that if the user updates the pawn's
// age in a way that switches them back and forth from adult to child (which nulls out the adulthood
// value in the Pawn), we can remember what the value was and restore it.
- protected Backstory lastSelectedAdulthoodBackstory = null;
+ public BackstoryDef LastSelectedAdulthoodBackstory = null;
+ public BackstoryDef LastSelectedChildhoodBackstory = null;
// A GUID provides a unique identifier for the CustomPawn.
protected string id;
- protected CustomHeadType headType;
+ //protected CustomHeadType headType;
protected List implants = new List();
protected List injuries = new List();
@@ -94,6 +95,11 @@ public bool Hidden {
}
}
+ public XenotypeDef RandomizeXenotype { get; set; }
+ public CustomXenotype RandomizeCustomXenotype { get; set; }
+ public bool RandomizeAnyNonArchite { get; set; }
+ public DevelopmentalStage RandomizeDevelopmentalStage { get; set; }
+
public CustomFaction Faction {
get {
return faction;
@@ -129,6 +135,12 @@ public AlienRace AlienRace {
}
}
+ public bool IsAlien {
+ get {
+ return alienRace != null && Pawn.def.defName != "Human";
+ }
+ }
+
public bool HasCustomBodyParts {
get {
return bodyParts.Count > 0;
@@ -162,10 +174,10 @@ public float Certainty {
public Color HairColor {
get {
- return pawn.story.hairColor;
+ return pawn.story.HairColor;
}
set {
- pawn.story.hairColor = value;
+ pawn.story.HairColor = value;
MarkPortraitAsDirty();
}
}
@@ -225,7 +237,7 @@ public void UpdatePortrait() {
}
public RenderTexture GetPortrait(Vector2 size) {
- return PortraitsCache.Get(Pawn, size, Rot4.South, new Vector3(0, 0, 0), 1.0f);
+ return PortraitsCache.Get(Pawn, size, Rot4.South, new Vector3(0, 0, 0), 1.0f, supersample: true, compensateForUIScale: true, renderClothes: true, renderHeadgear: true, overrideApparelColors: null, overrideHairColor: null, stylingStation: true);
}
public void InitializeWithPawn(Pawn pawn) {
@@ -279,26 +291,22 @@ public void InitializeWithPawn(Pawn pawn) {
}
}
- // Initialize head type.
- CustomHeadType headType = PrepareCarefully.Instance.Providers.HeadTypes.FindHeadTypeForPawn(pawn);
- if (headType != null) {
- this.headType = headType;
- }
- else {
- this.headType = null;
- }
-
// Reset CustomPawn cached values.
ResetApparel();
ResetCachedIncapableOf();
- ResetCachedHead();
// Copy the adulthood backstory or set a random one if it's null.
- this.LastSelectedAdulthoodBackstory = pawn.story.adulthood;
+ this.LastSelectedAdulthoodBackstory = pawn.story.Adulthood;
// Evaluate all hediffs.
InitializeInjuriesAndImplantsFromPawn(pawn);
+ if (ModsConfig.BiotechActive) {
+ RandomizeXenotype = pawn.genes.Xenotype;
+ RandomizeCustomXenotype = pawn.genes.CustomXenotype;
+ RandomizeDevelopmentalStage = pawn.DevelopmentalStage;
+ }
+
// Set the alien race, if any.
alienRace = PrepareCarefully.Instance.Providers.AlienRaces.GetAlienRace(pawn.def);
@@ -340,6 +348,9 @@ public void InitializeInjuriesAndImplantsFromPawn(Pawn pawn) {
if (getsPermanent != null) {
injury.PainFactor = getsPermanent.PainFactor;
}
+
+ injury.Chemical = (hediff as Hediff_ChemicalDependency)?.chemical;
+
injuries.Add(injury);
}
else {
@@ -350,9 +361,17 @@ public void InitializeInjuriesAndImplantsFromPawn(Pawn pawn) {
implant.recipe = implantRecipe;
implant.BodyPartRecord = hediff.Part;
implant.Hediff = hediff;
+ implant.HediffDef = hediff?.def;
implants.Add(implant);
//Logger.Debug("Found implant recipes for {" + hediff.def.defName + "} for part {" + hediff.Part?.LabelCap + "}");
}
+ else if (hediff.def.defName == "MechlinkImplant") {
+ Implant implant = new Implant();
+ implant.BodyPartRecord = hediff.Part;
+ implant.Hediff = hediff;
+ implant.HediffDef = hediff?.def;
+ implants.Add(implant);
+ }
else if (hediff.def.defName != "MissingBodyPart") {
Logger.Warning("Could not add hediff {" + hediff.def.defName + "} to the pawn because no recipe adds it to the body part {" + (hediff.Part?.def?.defName ?? "WholeBody") + "}");
}
@@ -428,20 +447,20 @@ protected void InitializeSkillLevelsAndPassions() {
}
}
- public Backstory LastSelectedAdulthoodBackstory {
- get {
- if (lastSelectedAdulthoodBackstory != null) {
- return lastSelectedAdulthoodBackstory;
- }
- else {
- lastSelectedAdulthoodBackstory = Randomizer.RandomAdulthood(this);
- return lastSelectedAdulthoodBackstory;
- }
- }
- set {
- lastSelectedAdulthoodBackstory = value;
- }
- }
+ //public BackstoryDef LastSelectedAdulthoodBackstory {
+ // get {
+ // if (lastSelectedAdulthoodBackstory != null) {
+ // return lastSelectedAdulthoodBackstory;
+ // }
+ // else {
+ // lastSelectedAdulthoodBackstory = Randomizer.RandomAdulthood(this);
+ // return lastSelectedAdulthoodBackstory;
+ // }
+ // }
+ // set {
+ // lastSelectedAdulthoodBackstory = value;
+ // }
+ //}
public void ClearApparel() {
this.pawn.apparel.DestroyAll();
@@ -449,15 +468,16 @@ public void ClearApparel() {
public void CopyAppearance(Pawn pawn) {
this.HairDef = pawn.story.hairDef;
- this.pawn.story.hairColor = pawn.story.hairColor;
+ this.pawn.story.HairColor = pawn.story.HairColor;
this.pawn.story.bodyType = pawn.story.bodyType;
if (pawn.style != null && this.Pawn.style != null) {
this.Beard = pawn.style.beardDef;
this.FaceTattoo = pawn.style.FaceTattoo;
this.BodyTattoo = pawn.style.BodyTattoo;
}
- this.HeadGraphicPath = pawn.story.HeadGraphicPath;
- this.MelaninLevel = pawn.story.melanin;
+ //this.HeadGraphicPath = pawn.story.HeadGraphicPath;
+ this.HeadType = pawn.story.headType;
+ this.MelaninLevel = pawn.genes.GetMelaninGene().minMelanin;
this.Pawn.apparel.DestroyAll();
foreach (var layer in PrepareCarefully.Instance.Providers.PawnLayers.GetLayersForPawn(this)) {
if (layer.Apparel) {
@@ -510,14 +530,14 @@ public void ComputeSkillLevelModifiers() {
protected int ComputeSkillModifier(SkillDef def) {
int value = 0;
- if (pawn.story != null && pawn.story.childhood != null && pawn.story.childhood.skillGainsResolved != null) {
- if (pawn.story.childhood.skillGainsResolved.ContainsKey(def)) {
- value += pawn.story.childhood.skillGainsResolved[def];
+ if (pawn.story != null && pawn.story.Childhood != null && pawn.story.Childhood.skillGains != null) {
+ if (pawn.story.Childhood.skillGains.ContainsKey(def)) {
+ value += pawn.story.Childhood.skillGains[def];
}
}
- if (pawn.story != null && pawn.story.adulthood != null && pawn.story.adulthood.skillGainsResolved != null) {
- if (pawn.story.adulthood.skillGainsResolved.ContainsKey(def)) {
- value += pawn.story.adulthood.skillGainsResolved[def];
+ if (pawn.story != null && pawn.story.Adulthood != null && pawn.story.Adulthood.skillGains != null) {
+ if (pawn.story.Adulthood.skillGains.ContainsKey(def)) {
+ value += pawn.story.Adulthood.skillGains[def];
}
}
foreach (Trait trait in this.Pawn.story.traits.allTraits) {
@@ -749,10 +769,10 @@ public Pawn Pawn {
public string Label {
get {
NameTriple name = pawn.Name as NameTriple;
- if (pawn.story.adulthood == null) {
+ if (pawn.story.Adulthood == null) {
return name.Nick;
}
- return name.Nick + ", " + pawn.story.adulthood.TitleShortFor(Gender);
+ return name.Nick + ", " + pawn.story.Adulthood.TitleShortFor(Gender);
}
}
@@ -985,10 +1005,10 @@ public string ProfessionLabel {
public string ProfessionLabelShort {
get {
if (IsAdult) {
- return Adulthood.TitleShortCapFor(Gender);
+ return Adulthood.TitleShortFor(Gender).CapitalizeFirst();
}
else {
- return Childhood.TitleShortCapFor(Gender);
+ return Childhood.TitleShortFor(Gender).CapitalizeFirst();
}
}
}
@@ -1109,29 +1129,29 @@ public string ApparelConflict {
}
}
- public Backstory Childhood {
+ public BackstoryDef Childhood {
get {
- return pawn.story.childhood;
+ return pawn.story.Childhood;
}
set {
- pawn.story.childhood = value;
+ pawn.story.Childhood = value;
ResetBackstories();
}
}
- public Backstory Adulthood {
+ public BackstoryDef Adulthood {
get {
- return pawn.story.adulthood;
+ return pawn.story.Adulthood;
}
set {
if (value != null) {
LastSelectedAdulthoodBackstory = value;
}
if (IsAdult) {
- pawn.story.adulthood = value;
+ pawn.story.Adulthood = value;
}
else {
- pawn.story.adulthood = null;
+ pawn.story.Adulthood = null;
}
ResetBackstories();
}
@@ -1147,46 +1167,15 @@ public void ResetBackstories() {
UpdateSkillLevelsForNewBackstoryOrTrait();
}
- public CustomHeadType HeadType {
+ public HeadTypeDef HeadType {
get {
- return headType;
+ return pawn.story.headType;
}
set {
- this.headType = value;
- //Logger.Debug("Setting pawn headType to " + value);
- this.pawn.story.crownType = value.CrownType != CrownType.Undefined ? value.CrownType : CrownType.Average;
- ThingComp alienComp = ProviderAlienRaces.FindAlienCompForPawn(pawn);
- if (alienComp != null) {
- ReflectionUtil.GetPublicField(alienComp, "crownType").SetValue(alienComp, headType.AlienCrownType);
- }
- ResetCachedHead();
- MarkPortraitAsDirty();
- }
- }
-
- public string HeadGraphicPath {
- get {
- return pawn.story.HeadGraphicPath;
- }
- set {
- CustomHeadType headType = PrepareCarefully.Instance.Providers.HeadTypes.FindHeadType(pawn.def, value);
- if (headType != null) {
- HeadType = headType;
- }
- else {
- Logger.Warning("Could not find a head type for the graphic path: " + value);
- }
- ResetCachedHead();
+ pawn.story.headType = value;
MarkPortraitAsDirty();
}
}
-
- protected void SetHeadGraphicPathOnPawn(Pawn pawn, string value) {
- // Need to use reflection to set the private field.
- typeof(Pawn_StoryTracker).GetField("headGraphicPath", BindingFlags.Instance | BindingFlags.NonPublic)
- .SetValue(pawn.story, value);
- }
-
protected string FilterHeadPathForGender(string path) {
if (pawn.gender == Gender.Male) {
return path.Replace("Female", "Male");
@@ -1323,18 +1312,33 @@ public Color SkinColor {
}
}
}
+ else {
+ bool removeOverride = false;
+ var melaninGeneDef = pawn.genes.GetMelaninGene();
+ Gene activeSkinColorGene = null;
+ if (pawn?.genes?.GenesListForReading != null) {
+ activeSkinColorGene = pawn.genes.GenesListForReading.Where(g => g.Active && g.def.skinColorOverride.HasValue && g.overriddenByGene == null).FirstOrDefault();
+ }
+ if (activeSkinColorGene == null && melaninGeneDef?.skinColorBase != null && melaninGeneDef.skinColorBase == value) {
+ removeOverride = true;
+ }
+ if (removeOverride) {
+ this.pawn.story.skinColorOverride = null;
+ }
+ else {
+ this.pawn.story.skinColorOverride = value;
+ }
+ MarkPortraitAsDirty();
+ }
}
}
public float MelaninLevel {
get {
- return pawn.story.melanin;
+ return pawn.genes.GetMelaninGene().minMelanin;
}
set {
- pawn.story.melanin = value;
- if (alienRace != null) {
- SkinColor = PawnSkinColors.GetSkinColor(value);
- }
+ SkinColor = PawnSkinColors.GetSkinColor(value);
MarkPortraitAsDirty();
}
}
@@ -1367,15 +1371,20 @@ public int BiologicalAge {
return pawn.ageTracker.AgeBiologicalYears;
}
set {
+ bool wasNewborn = IsNewborn();
+ bool wasJuvenile = IsJuvenile();
+ bool wasAdult = IsAdult;
+ bool hadBothBackstories = !wasNewborn && !wasJuvenile;
+
long years = pawn.ageTracker.AgeBiologicalYears;
long diff = value - years;
pawn.ageTracker.AgeBiologicalTicks += diff * 3600000L;
- if (IsAdult && pawn.story.adulthood == null) {
- pawn.story.adulthood = LastSelectedAdulthoodBackstory;
+ if (IsAdult && pawn.story.Adulthood == null) {
+ pawn.story.Adulthood = LastSelectedAdulthoodBackstory;
ResetBackstories();
}
- else if (!IsAdult && pawn.story.adulthood != null) {
- pawn.story.adulthood = null;
+ else if (!IsAdult && pawn.story.Adulthood != null) {
+ pawn.story.Adulthood = null;
ResetBackstories();
}
pawn.ClearCachedLifeStage();
@@ -1383,19 +1392,53 @@ public int BiologicalAge {
MarkPortraitAsDirty();
}
}
+ public long BiologicalAgeInTicks {
+ get {
+ return pawn.ageTracker.AgeBiologicalTicks;
+ }
+ }
- protected void ResetCachedHead() {
- if (headType != null) {
- // Get the matching head type for the pawn's current gender. We do this in case the user switches the
- // gender, swapping to the correct head type if necessary.
- CustomHeadType filteredHeadType = PrepareCarefully.Instance.Providers.HeadTypes.FindHeadTypeForGender(pawn.def, headType, Gender);
- if (filteredHeadType == null) {
- Logger.Warning("No filtered head type found"); //TODO
- }
- SetHeadGraphicPathOnPawn(pawn, filteredHeadType.GraphicPath);
+ public long ChronologicalAgeInTicks {
+ get {
+ return pawn.ageTracker.AgeChronologicalTicks;
+ }
+ }
+ public int BiologicalAgeInYears {
+ get {
+ return pawn.ageTracker.AgeBiologicalYears;
}
}
+ public int ChronologicalAgeInYears {
+ get {
+ return pawn.ageTracker.AgeChronologicalYears;
+ }
+ }
+
+ public int ChronologicalAgeInDays {
+ get {
+ return (int)(pawn.ageTracker.AgeChronologicalTicks / AgeModifier.TicksPerDay);
+ }
+ }
+ public int BiologicalAgeInDays {
+ get {
+ return (int)(pawn.ageTracker.AgeBiologicalTicks / AgeModifier.TicksPerDay);
+ }
+ }
+
+ public bool IsNewborn() {
+ DevelopmentalStage? d = Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ return d.HasValue ? d.Value.Newborn() : false;
+ }
+ public bool IsJuvenile() {
+ DevelopmentalStage? d = Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ return d.HasValue ? d.Value.Juvenile() : false;
+ }
+ //public bool IsAdult() {
+ // DevelopmentalStage? d = Pawn.ageTracker?.CurLifeStage?.developmentalStage;
+ // return d.HasValue ? d.Value.Adult() : false;
+ //}
+
protected void ResetGender() {
List bodyTypes = PrepareCarefully.Instance.Providers.BodyTypes.GetBodyTypesForPawn(this);
if (pawn.gender == Gender.Female) {
@@ -1409,6 +1452,9 @@ protected void ResetGender() {
BodyType = BodyTypeDefOf.Female;
}
}
+ if (HeadType.gender == Gender.Male) {
+ HeadType = PrepareCarefully.Instance.Providers.HeadTypes.FindMatchingHeadTypeForOtherGenderOrDefault(HeadType, pawn.gender);
+ }
}
else {
if (HairDef.styleGender == StyleGender.Female) {
@@ -1421,8 +1467,10 @@ protected void ResetGender() {
BodyType = BodyTypeDefOf.Male;
}
}
+ if (HeadType.gender == Gender.Female) {
+ HeadType = PrepareCarefully.Instance.Providers.HeadTypes.FindMatchingHeadTypeForOtherGenderOrDefault(HeadType, pawn.gender);
+ }
}
- ResetCachedHead();
}
public string ResetCachedIncapableOf() {
@@ -1511,12 +1559,16 @@ public void AddApparelToPawn(Pawn targetPawn, PawnLayer layer) {
}
public void AddInjury(Injury injury) {
- injuries.Add(injury);
- bodyParts.Add(injury);
+ AddInjuryDirect(injury);
ApplyInjuriesAndImplantsToPawn();
InitializeInjuriesAndImplantsFromPawn(this.pawn);
}
+ public void AddInjuryDirect(Injury injury) {
+ injuries.Add(injury);
+ bodyParts.Add(injury);
+ }
+
public void UpdateImplants(List implants) {
List implantsToRemove = new List();
foreach (var bodyPart in bodyParts) {
@@ -1535,7 +1587,7 @@ public void UpdateImplants(List implants) {
InitializeInjuriesAndImplantsFromPawn(this.pawn);
}
- protected void ApplyInjuriesAndImplantsToPawn() {
+ public void ApplyInjuriesAndImplantsToPawn() {
this.pawn.health.Reset();
List injuriesToRemove = new List();
foreach (var injury in injuries) {
@@ -1591,14 +1643,20 @@ public void RemoveCustomBodyParts(BodyPartRecord part) {
}
public void AddImplant(Implant implant) {
+ if (AddImplantDirect(implant)) {
+ ApplyInjuriesAndImplantsToPawn();
+ InitializeInjuriesAndImplantsFromPawn(this.pawn);
+ }
+ }
+ public bool AddImplantDirect(Implant implant) {
if (implant != null && implant.BodyPartRecord != null) {
implants.Add(implant);
bodyParts.Add(implant);
- ApplyInjuriesAndImplantsToPawn();
- InitializeInjuriesAndImplantsFromPawn(this.pawn);
+ return true;
}
else {
Logger.Warning("Discarding implant because of missing body part: " + implant.BodyPartRecord.def.defName);
+ return false;
}
}
diff --git a/Source/DialogPawnKinds.cs b/Source/DialogPawnKinds.cs
index fab0412..17787e1 100644
--- a/Source/DialogPawnKinds.cs
+++ b/Source/DialogPawnKinds.cs
@@ -5,7 +5,39 @@
using Verse;
using Verse.Sound;
namespace EdB.PrepareCarefully {
+ public class PawnKindOption {
+ public PawnKindOption() {
+ this.FactionDef = null;
+ this.KindDef = null;
+ }
+ public PawnKindOption(FactionDef factionDef, PawnKindDef kindDef) {
+ this.FactionDef = factionDef;
+ this.KindDef = kindDef;
+ }
+
+ public FactionDef FactionDef { get; set; }
+ public PawnKindDef KindDef { get; set; }
+
+ public override bool Equals(object obj) {
+ return obj is PawnKindOption option &&
+ EqualityComparer.Default.Equals(FactionDef, option.FactionDef) &&
+ EqualityComparer.Default.Equals(KindDef, option.KindDef);
+ }
+
+ public override int GetHashCode() {
+ var hashCode = 101273788;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(FactionDef);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(KindDef);
+ return hashCode;
+ }
+
+ public override string ToString() {
+ return "{ FactionDef = " + FactionDef?.defName + ", KindDef = " + KindDef?.defName + "}";
+ }
+ }
+
public class DialogPawnKinds : Window {
+
public Vector2 ContentMargin { get; protected set; }
public Vector2 WindowSize { get; protected set; }
public Vector2 ButtonSize { get; protected set; }
@@ -25,7 +57,7 @@ public class DialogPawnKinds : Window {
protected string headerLabel;
protected bool resizeDirtyFlag = true;
protected bool confirmed = false;
- protected PawnKindDef scrollTo = null;
+ protected PawnKindOption scrollToWhenFirstOpened = null;
protected LabelTrimmer labelTrimmer = new LabelTrimmer();
public DialogPawnKinds() {
this.closeOnCancel = true;
@@ -35,7 +67,7 @@ public DialogPawnKinds() {
Resize();
}
- public PawnKindDef Selected {
+ public PawnKindOption Selected {
get;
set;
}
@@ -56,22 +88,22 @@ public Action CloseAction {
get;
set;
}
- public Action SelectAction {
+ public Action SelectAction {
get;
set;
}
- public HashSet DisabledOptions {
+ public HashSet DisabledOptions {
get;
set;
}
- protected WidgetTable table = new WidgetTable();
+ protected WidgetTable table = new WidgetTable();
public string ConfirmButtonLabel = "EdB.PC.Common.Select";
public string CancelButtonLabel = "EdB.PC.Common.Cancel";
- public void ScrollTo(PawnKindDef kindDef) {
- this.scrollTo = kindDef;
+ public void ScrollToWhenOpened(PawnKindOption kindDef) {
+ this.scrollToWhenFirstOpened = kindDef;
}
protected void MarkResizeFlagDirty() {
resizeDirtyFlag = true;
@@ -123,7 +155,7 @@ protected void Resize() {
labelTrimmer.Rect = new Rect(0, 0, nameSize.x, nameSize.y);
- table = new WidgetTable();
+ table = new WidgetTable();
table.Rect = new Rect(Vector2.zero, ContentRect.size);
table.RowHeight = 42;
table.RowGroupHeaderHeight = RowGroupHeaderHeight;
@@ -131,48 +163,48 @@ protected void Resize() {
table.AlternateRowColor = new Color(0, 0, 0, 0);
table.SelectedRowColor = new Color(0, 0, 0, 0);
table.SupportSelection = true;
- table.SelectedAction = (PawnKindDef pawnKind) => {
- if (!DisabledOptions.Contains(pawnKind)) {
+ table.SelectedAction = (PawnKindOption kind) => {
+ if (!DisabledOptions.Contains(kind)) {
SoundDefOf.Tick_Tiny.PlayOneShotOnCamera();
- Select(pawnKind);
+ Select(kind);
}
};
- table.AddColumn(new WidgetTable.Column() {
+ table.AddColumn(new WidgetTable.Column() {
Name = "Name",
Width = nameSize.x,
AdjustForScrollbars = true,
- DrawAction = (PawnKindDef pawnKind, Rect rect, WidgetTable.Metadata metadata) => {
+ DrawAction = (PawnKindOption kind, Rect rect, WidgetTable.Metadata metadata) => {
Text.Anchor = TextAnchor.MiddleLeft;
Text.Font = GameFont.Small;
- if (this.ShowRace && pawnKind.race != null) {
+ if (this.ShowRace && kind.KindDef.race != null) {
Rect nameRect = new Rect(rect.x + nameOffset, rect.y + 5, rect.width, 22);
- Widgets.Label(nameRect, labelTrimmer.TrimLabelIfNeeded(pawnKind.LabelCap));
+ Widgets.Label(nameRect, labelTrimmer.TrimLabelIfNeeded(kind.KindDef.LabelCap));
Rect raceRect = new Rect(rect.x + nameOffset, nameRect.yMax - 5, rect.width, nameSize.y - 25);
Text.Font = GameFont.Tiny;
GUI.color = Style.ColorTextSecondary;
- Widgets.Label(raceRect, labelTrimmer.TrimLabelIfNeeded(pawnKind.race.LabelCap));
+ Widgets.Label(raceRect, labelTrimmer.TrimLabelIfNeeded(kind.KindDef.race.LabelCap));
GUI.color = Color.white;
Text.Font = GameFont.Small;
}
else {
- Widgets.Label(new Rect(rect.x + nameOffset, rect.y + 1, rect.width, nameSize.y), pawnKind.LabelCap);
+ Widgets.Label(new Rect(rect.x + nameOffset, rect.y + 1, rect.width, nameSize.y), kind.KindDef.LabelCap);
}
Text.Anchor = TextAnchor.UpperLeft;
}
});
- table.AddColumn(new WidgetTable.Column() {
+ table.AddColumn(new WidgetTable.Column() {
Name = "RadioButton",
Width = radioWidth,
- DrawAction = (PawnKindDef pawnKind, Rect rect, WidgetTable.Metadata metadata) => {
- if (DisabledOptions != null && DisabledOptions.Contains(pawnKind)) {
+ DrawAction = (PawnKindOption kind, Rect rect, WidgetTable.Metadata metadata) => {
+ if (DisabledOptions != null && DisabledOptions.Contains(kind)) {
GUI.color = Style.ColorControlDisabled;
GUI.color = new Color(1, 1, 1, 0.28f);
GUI.DrawTexture(new Rect(rect.x, rect.MiddleY() - 12, 24, 24), Textures.TextureRadioButtonOff);
GUI.color = Color.white;
}
else {
- if (Widgets.RadioButton(new Vector2(rect.x, rect.MiddleY() - 12), this.Selected == pawnKind)) {
- Select(pawnKind);
+ if (Widgets.RadioButton(new Vector2(rect.x, rect.MiddleY() - 12), EqualityComparer.Default.Equals(this.Selected, kind))) {
+ Select(kind);
}
}
}
@@ -180,18 +212,18 @@ protected void Resize() {
resizeDirtyFlag = false;
}
- protected void Select(PawnKindDef pawnKind) {
- this.Selected = pawnKind;
+ protected void Select(PawnKindOption kind) {
+ this.Selected = kind;
if (SelectAction != null) {
- SelectAction(pawnKind);
+ SelectAction(kind);
}
}
- public IEnumerable PawnKinds {
+ public IEnumerable FactionPawnKinds {
get; set;
}
- public IEnumerable.RowGroup> RowGroups {
+ public IEnumerable.RowGroup> RowGroups {
get; set;
}
@@ -207,9 +239,9 @@ public override void DoWindowContents(Rect inRect) {
if (resizeDirtyFlag) {
Resize();
}
- if (scrollTo != null) {
- table.ScrollTo(scrollTo);
- scrollTo = null;
+ if (scrollToWhenFirstOpened != null) {
+ table.ScrollTo(scrollToWhenFirstOpened);
+ scrollToWhenFirstOpened = null;
}
GUI.color = Color.white;
Text.Font = GameFont.Medium;
@@ -225,7 +257,7 @@ public override void DoWindowContents(Rect inRect) {
table.Draw(RowGroups);
}
else {
- table.Draw(PawnKinds);
+ table.Draw(FactionPawnKinds);
}
}
finally {
diff --git a/Source/ExtensionsBackstory.cs b/Source/ExtensionsBackstory.cs
index 6d38c99..b4d44af 100644
--- a/Source/ExtensionsBackstory.cs
+++ b/Source/ExtensionsBackstory.cs
@@ -13,7 +13,7 @@ public static class ExtensionsBackstory {
"pirate king"
};
- public static string CheckedDescriptionFor(this Backstory backstory, Pawn pawn) {
+ public static string CheckedDescriptionFor(this BackstoryDef backstory, Pawn pawn) {
if (ProblemBackstories.Contains(backstory.untranslatedTitle)) {
return PartialDescriptionFor(backstory);
}
@@ -28,13 +28,13 @@ public static string CheckedDescriptionFor(this Backstory backstory, Pawn pawn)
// EVERY RELEASE:
// This is a copy of Backstory.FullDescriptionFor() that only includes the disabled work types and the skill adjustments.
// Every release, we should evaluate that method to make sure that the logic has not changed.
- public static string PartialDescriptionFor(this Backstory backstory) {
+ public static string PartialDescriptionFor(this BackstoryDef backstory) {
StringBuilder stringBuilder = new StringBuilder();
List allDefsListForReading = DefDatabase.AllDefsListForReading;
for (int i = 0; i < allDefsListForReading.Count; i++) {
SkillDef skillDef = allDefsListForReading[i];
- if (backstory.skillGainsResolved.ContainsKey(skillDef)) {
- stringBuilder.AppendLine(skillDef.skillLabel.CapitalizeFirst() + ": " + backstory.skillGainsResolved[skillDef].ToString("+##;-##"));
+ if (backstory.skillGains.ContainsKey(skillDef)) {
+ stringBuilder.AppendLine(skillDef.skillLabel.CapitalizeFirst() + ": " + backstory.skillGains[skillDef].ToString("+##;-##"));
}
}
stringBuilder.AppendLine();
diff --git a/Source/ExtensionsPawn.cs b/Source/ExtensionsPawn.cs
index 834ea37..98f2d38 100644
--- a/Source/ExtensionsPawn.cs
+++ b/Source/ExtensionsPawn.cs
@@ -123,6 +123,7 @@ public static void ClearCaches(this Pawn pawn) {
pawn.ClearCachedHealth();
pawn.ClearCachedLifeStage();
pawn.ClearCachedDisabledSkillRecords();
+ pawn.ClearCachedPortraits();
}
public static void ClearCachedDisabledSkillRecords(this Pawn pawn) {
diff --git a/Source/Field.cs b/Source/Field.cs
index 5f5f890..daf9bb6 100644
--- a/Source/Field.cs
+++ b/Source/Field.cs
@@ -16,6 +16,7 @@ public class Field {
private Action tipAction;
private Color color = Style.ColorText;
private bool enabled = true;
+ private bool nextPreviousButtonsHidden = false;
public Field() {
}
public Rect Rect {
@@ -90,6 +91,14 @@ public bool Enabled {
enabled = value;
}
}
+ public bool NextPreviousButtonsHidden {
+ get {
+ return nextPreviousButtonsHidden;
+ }
+ set {
+ nextPreviousButtonsHidden = value;
+ }
+ }
public Action DrawIconFunc = null;
public Func IconSizeFunc = null;
@@ -100,11 +109,11 @@ public void Draw() {
try {
// Adjust the width of the rectangle if the field has next and previous buttons.
Rect fieldRect = rect;
- if (previousAction != null) {
+ if (previousAction != null || nextPreviousButtonsHidden) {
fieldRect.x += 12;
fieldRect.width -= 12;
}
- if (nextAction != null) {
+ if (nextAction != null || nextPreviousButtonsHidden) {
fieldRect.width -= 12;
}
diff --git a/Source/FilterBackstoryMatchesFaction.cs b/Source/FilterBackstoryMatchesFaction.cs
index 3f9e6a2..9c96f71 100644
--- a/Source/FilterBackstoryMatchesFaction.cs
+++ b/Source/FilterBackstoryMatchesFaction.cs
@@ -6,10 +6,10 @@
using Verse;
namespace EdB.PrepareCarefully {
- class FilterBackstoryMatchesFaction : Filter {
+ class FilterBackstoryMatchesFaction : Filter {
public FilterBackstoryMatchesFaction() {
this.LabelShort = this.LabelFull = "EdB.PC.Dialog.Backstory.Filter.MatchesFaction".Translate();
- this.FilterFunction = (Backstory backstory) => {
+ this.FilterFunction = (BackstoryDef backstory) => {
CustomPawn pawn = PrepareCarefully.Instance.State.CurrentPawn;
PawnKindDef kindDef = pawn.OriginalKindDef;
if (kindDef == null) {
diff --git a/Source/FilterBackstoryNoDisabledWorkTypes.cs b/Source/FilterBackstoryNoDisabledWorkTypes.cs
index f23d1c2..148a881 100644
--- a/Source/FilterBackstoryNoDisabledWorkTypes.cs
+++ b/Source/FilterBackstoryNoDisabledWorkTypes.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,10 +6,10 @@
using Verse;
namespace EdB.PrepareCarefully {
- class FilterBackstoryNoDisabledWorkTypes : Filter {
+ class FilterBackstoryNoDisabledWorkTypes : Filter {
public FilterBackstoryNoDisabledWorkTypes() {
this.LabelShort = this.LabelFull = "EdB.PC.Dialog.Backstory.Filter.NoDisabledWorkTypes".Translate();
- this.FilterFunction = (Backstory backstory) => {
+ this.FilterFunction = (BackstoryDef backstory) => {
return (backstory.DisabledWorkTypes.FirstOrDefault() == null);
};
}
diff --git a/Source/FilterBackstoryNoPenalties.cs b/Source/FilterBackstoryNoPenalties.cs
index 86681ad..9eba173 100644
--- a/Source/FilterBackstoryNoPenalties.cs
+++ b/Source/FilterBackstoryNoPenalties.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,14 +6,14 @@
using Verse;
namespace EdB.PrepareCarefully {
- class FilterBackstoryNoPenalties : Filter {
+ class FilterBackstoryNoPenalties : Filter {
public FilterBackstoryNoPenalties() {
this.LabelShort = this.LabelFull = "EdB.PC.Dialog.Backstory.Filter.NoSkillPenalties".Translate();
this.FilterFunction = (backstory) => {
- if (backstory.skillGainsResolved.Count == 0) {
+ if (backstory.skillGains.Count == 0) {
return true;
}
- foreach (var gain in backstory.skillGainsResolved.Values) {
+ foreach (var gain in backstory.skillGains.Values) {
if (gain < 0) {
return false;
}
diff --git a/Source/FilterBackstorySkillAdjustment.cs b/Source/FilterBackstorySkillAdjustment.cs
index 07a731b..7e74589 100644
--- a/Source/FilterBackstorySkillAdjustment.cs
+++ b/Source/FilterBackstorySkillAdjustment.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,7 +6,7 @@
using Verse;
namespace EdB.PrepareCarefully {
- class FilterBackstorySkillAdjustment : Filter {
+ class FilterBackstorySkillAdjustment : Filter {
private int BonusOrPenalty {
get;
set;
@@ -26,9 +26,9 @@ public FilterBackstorySkillAdjustment(SkillDef skillDef, int bonusOrPenalty) {
this.LabelShort = "EdB.PC.Dialog.Backstory.Filter.SkillBonus".Translate(this.SkillDef.LabelCap, bonusOrPenalty);
this.LabelFull = "EdB.PC.Dialog.Backstory.Filter.SkillBonusFull".Translate(this.SkillDef.LabelCap, bonusOrPenalty);
}
- this.FilterFunction = (Backstory backstory) => {
- if (this.SkillDef != null && backstory.skillGainsResolved.ContainsKey(this.SkillDef)) {
- int value = backstory.skillGainsResolved[skillDef];
+ this.FilterFunction = (BackstoryDef backstory) => {
+ if (this.SkillDef != null && backstory.skillGains.ContainsKey(this.SkillDef)) {
+ int value = backstory.skillGains[skillDef];
if (bonusOrPenalty > 0) {
return value >= bonusOrPenalty;
}
@@ -39,7 +39,7 @@ public FilterBackstorySkillAdjustment(SkillDef skillDef, int bonusOrPenalty) {
return false;
};
}
- public override bool ConflictsWith(Filter filter) {
+ public override bool ConflictsWith(Filter filter) {
if (filter as FilterBackstorySkillAdjustment == null) {
return false;
}
diff --git a/Source/HarmonyPatches.cs b/Source/HarmonyPatches.cs
index 1076258..3ac9930 100644
--- a/Source/HarmonyPatches.cs
+++ b/Source/HarmonyPatches.cs
@@ -65,8 +65,13 @@ static void Postfix() {
class PrepareCarefullyButtonPatch {
static void Postfix(Page_ConfigureStartingPawns __instance, ref Rect rect) {
Vector2 BottomButSize = new Vector2(150f, 38f);
- float num = rect.height + 45f;
- Rect rect4 = new Rect(rect.x + rect.width / 2f - BottomButSize.x / 2f, num, BottomButSize.x, BottomButSize.y);
+ float halfButtonWidth = 75f;
+ float num = rect.height + 55f;
+ Rect rect4 = new Rect(rect.width / 2 - halfButtonWidth, num, BottomButSize.x, BottomButSize.y);
+ if (ModsConfig.BiotechActive) {
+ float w = (rect.width * 0.5f) - 16f - BottomButSize.HalfX();
+ rect4 = new Rect(16f + (w * 0.5f), num, BottomButSize.x, BottomButSize.y);
+ }
if (Widgets.ButtonText(rect4, "EdB.PC.Page.Button.PrepareCarefully".Translate(), true, false, true)) {
// Version check
if (VersionControl.CurrentVersion < PrepareCarefully.MinimumGameVersion) {
diff --git a/Source/Implant.cs b/Source/Implant.cs
index da3c6b8..f8efab2 100644
--- a/Source/Implant.cs
+++ b/Source/Implant.cs
@@ -12,6 +12,7 @@ public class Implant : CustomBodyPart {
public string label = "";
public RecipeDef recipe = null;
protected Hediff hediff = null;
+ protected HediffDef hediffDef = null;
protected string tooltip;
@@ -33,6 +34,12 @@ public Hediff Hediff {
set => hediff = value;
}
+ public HediffDef HediffDef {
+ get => hediffDef;
+ set => hediffDef = value;
+ }
+
+
override public string ChangeName {
get {
return Label;
@@ -84,7 +91,7 @@ public override bool Equals(System.Object obj) {
return false;
}
- return (BodyPartRecord == option.BodyPartRecord) && (recipe == option.recipe);
+ return (BodyPartRecord == option.BodyPartRecord) && (recipe == option.recipe) && (hediffDef == option.hediffDef);
}
public bool Equals(Implant option) {
@@ -92,22 +99,25 @@ public bool Equals(Implant option) {
return false;
}
- return (BodyPartRecord == option.BodyPartRecord) && (recipe == option.recipe);
- }
-
- public override int GetHashCode() {
- unchecked {
- int a = BodyPartRecord != null ? BodyPartRecord.GetHashCode() : 0;
- int b = recipe != null ? recipe.GetHashCode() : 0;
- return 31 * a + b;
- }
+ return (BodyPartRecord == option.BodyPartRecord) && (recipe == option.recipe) && (hediffDef == option.hediffDef);
}
public override void AddToPawn(CustomPawn customPawn, Pawn pawn) {
- if (recipe != null && BodyPartRecord != null) {
+ Logger.Debug("Adding implant to pawn, recipe = " + this.recipe?.defName + ", hediff = " + this.hediffDef ?.defName);
+ if (BodyPartRecord == null) {
+ Logger.Warning("Could not add implant to pawn because no BodyPartRecord is defined");
+ }
+ if (recipe != null) {
this.hediff = HediffMaker.MakeHediff(recipe.addsHediff, pawn, BodyPartRecord);
pawn.health.AddHediff(hediff, BodyPartRecord, new DamageInfo?());
}
+ else if (hediffDef != null) {
+ this.hediff = HediffMaker.MakeHediff(hediffDef, pawn, BodyPartRecord);
+ pawn.health.AddHediff(hediff, BodyPartRecord, new DamageInfo?());
+ }
+ else {
+ Logger.Warning("Could not add implant to pawn because no RecipeDef or HediffDef is defined");
+ }
}
public bool ReplacesPart {
@@ -153,6 +163,14 @@ protected void InitializeTooltip() {
}
tooltip = stringBuilder.ToString();
}
+
+ public override int GetHashCode() {
+ var hashCode = -775691452;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(BodyPartRecord);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(recipe);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(hediffDef);
+ return hashCode;
+ }
}
}
diff --git a/Source/Injury.cs b/Source/Injury.cs
index 677971c..61016c0 100644
--- a/Source/Injury.cs
+++ b/Source/Injury.cs
@@ -38,6 +38,8 @@ public Hediff Hediff {
protected float? painFactor = null;
+ public ChemicalDef Chemical { get; set; }
+
public float Severity {
get {
return severity;
@@ -111,7 +113,6 @@ public override void AddToPawn(CustomPawn customPawn, Pawn pawn) {
if (getsPermanent != null) {
getsPermanent.IsPermanent = true;
Reflection.HediffComp_GetsPermanent.SetPainCategory(getsPermanent, PainCategoryForFloat(painFactor == null ? 0 : painFactor.Value));
- //ReflectionUtil.SetNonPublicField(getsPermanent, "painFactor", painFactor == null ? 0 : painFactor.Value);
}
pawn.health.AddHediff(hediff, BodyPartRecord);
@@ -138,6 +139,9 @@ public override void AddToPawn(CustomPawn customPawn, Pawn pawn) {
hediffLevel.SetLevelTo((int)Severity);
}
}
+ if (hediff is Hediff_ChemicalDependency chemicalDependency) {
+ chemicalDependency.chemical = Chemical;
+ }
pawn.health.AddHediff(hediff);
this.hediff = hediff;
}
@@ -147,6 +151,7 @@ public override void AddToPawn(CustomPawn customPawn, Pawn pawn) {
// Check the PainCategory enum to verify that we still only have 4 values and that their int values match the logic here.
// This method converts a float value into a PainCategory. It's here because we don't quite remember where that float
// value comes from and if it contain a value that won't map to one of the PainCategory enum values.
+ // Unchanged for 1.14
protected PainCategory PainCategoryForFloat(float value) {
int intValue = Mathf.FloorToInt(value);
if (intValue == 2) {
diff --git a/Source/InjuryOption.cs b/Source/InjuryOption.cs
index 0f60992..353beec 100644
--- a/Source/InjuryOption.cs
+++ b/Source/InjuryOption.cs
@@ -12,6 +12,7 @@ public class InjuryOption {
protected bool removesPart = false;
protected bool wholeBody = false;
protected string label = "?";
+ public bool Selectable { get; set; } = true;
public bool UsesSeverityPercentile {
get {
diff --git a/Source/OptionsHeadType.cs b/Source/OptionsHeadType.cs
index ca9227a..5036007 100644
--- a/Source/OptionsHeadType.cs
+++ b/Source/OptionsHeadType.cs
@@ -9,113 +9,36 @@
using UnityEngine;
using Verse;
using Verse.Sound;
+using System.Runtime.Remoting.Messaging;
namespace EdB.PrepareCarefully {
public class OptionsHeadType {
- protected List heads = new List();
- protected List headPaths = new List();
- protected List maleHeadTypes = new List();
- protected List femaleHeadTypes = new List();
- protected List noGenderHeaderTypes = new List();
- public Dictionary pathDictionary = new Dictionary();
- public List headTypes = new List();
+ protected List maleHeadTypes = new List();
+ protected List femaleHeadTypes = new List();
+ protected List noGenderHeaderTypes = new List();
+ public List headTypes = new List();
protected int count = 0;
public OptionsHeadType() {
}
- public void AddHeadType(CustomHeadType headType) {
+ public void AddHeadType(HeadTypeDef headType) {
headTypes.Add(headType);
- //Logger.Debug(headType.ToString());
- if (!headType.GraphicPath.NullOrEmpty() && !pathDictionary.ContainsKey(headType.GraphicPath)) {
- pathDictionary.Add(headType.GraphicPath, headType);
+ if (headType.gender == Gender.Male) {
+ maleHeadTypes.Add(headType);
}
- if (!headType.AlternateGraphicPath.NullOrEmpty() && !pathDictionary.ContainsKey(headType.AlternateGraphicPath)) {
- pathDictionary.Add(headType.AlternateGraphicPath, headType);
- }
- }
- public IEnumerable GetHeadTypesForGender(Gender gender) {
- return headTypes.Where((CustomHeadType headType) => {
- return (headType.Gender == gender || headType.Gender == null);
- });
- }
- public CustomHeadType FindHeadTypeForPawn(Pawn pawn) {
- var alienComp = ProviderAlienRaces.FindAlienCompForPawn(pawn);
- if (alienComp == null) {
- var result = FindHeadTypeByGraphicsPath(pawn.story.HeadGraphicPath);
- if (result == null) {
- Logger.Warning("Did not find head type for path: " + pawn.story.HeadGraphicPath);
- }
- return result;
- }
- else {
- string crownType = ProviderAlienRaces.GetCrownTypeFromComp(alienComp);
- var result = FindHeadTypeByCrownTypeAndGender(crownType, pawn.gender);
- if (result == null) {
- Logger.Warning("Did not find head type for alien crown type: " + crownType);
- }
- return result;
- }
- }
- public CustomHeadType FindHeadTypeByGraphicsPath(string graphicsPath) {
- if (pathDictionary.TryGetValue(graphicsPath, out CustomHeadType result)) {
- return result;
+ else if (headType.gender == Gender.Female) {
+ femaleHeadTypes.Add(headType);
}
else {
- return null;
+ noGenderHeaderTypes.Add(headType);
}
}
- public CustomHeadType FindHeadTypeByCrownType(string crownType) {
- return headTypes.Where(t => {
- return t.AlienCrownType == crownType;
- }).FirstOrDefault();
- }
- public CustomHeadType FindHeadTypeByCrownTypeAndGender(string crownType, Gender gender) {
- return headTypes.Where(t => {
- return t.AlienCrownType == crownType && (t.Gender == null || t.Gender == gender);
- }).FirstOrDefault();
+ public IEnumerable GetHeadTypesForGender(Gender gender) {
+ return headTypes.Where((HeadTypeDef headType) => {
+ return (headType.gender == gender || headType.gender == Gender.None);
+ });
}
- public CustomHeadType FindHeadTypeForGender(CustomHeadType headType, Gender gender) {
- if (headType.Gender == null || headType.Gender == gender) {
- return headType;
- }
-
- if (headType.AlienCrownType.NullOrEmpty()) {
- string graphicsPath = headType.GraphicPath;
- string prefixReplacementString = "/" + gender.ToString() + "_";
- string directoryReplacementString = "/" + gender.ToString() + "/";
- if (headType.Gender == Gender.Male) {
- graphicsPath = graphicsPath.Replace("/Male/", directoryReplacementString);
- graphicsPath = graphicsPath.Replace("/Male_", prefixReplacementString);
- }
- if (headType.Gender == Gender.Female) {
- graphicsPath = graphicsPath.Replace("/Female/", directoryReplacementString);
- graphicsPath = graphicsPath.Replace("/Female_", prefixReplacementString);
- }
- else {
- graphicsPath = graphicsPath.Replace("/None/", directoryReplacementString);
- graphicsPath = graphicsPath.Replace("/None_", prefixReplacementString);
- }
- CustomHeadType result = FindHeadTypeByGraphicsPath(graphicsPath);
- if (result == null) {
- Logger.Warning("Could not find head type for gender: " + graphicsPath);
- }
- return result != null ? result : headType;
- }
- else {
- Gender targetGender = gender;
- if (headType.Gender == Gender.Male) {
- targetGender = Gender.Female;
- }
- if (headType.Gender == Gender.Female) {
- targetGender = Gender.Male;
- }
- else {
- return headType;
- }
- var result = headTypes.Where(h => {
- return h.AlienCrownType == headType.AlienCrownType && h.Gender == targetGender;
- }).FirstOrDefault();
- return result != null ? result : headType;
- }
+ public HeadTypeDef FindHeadTypeForPawn(Pawn pawn) {
+ return pawn.story.headType;
}
}
}
diff --git a/Source/OptionsHealth.cs b/Source/OptionsHealth.cs
index 8ebc707..416fa23 100644
--- a/Source/OptionsHealth.cs
+++ b/Source/OptionsHealth.cs
@@ -232,6 +232,11 @@ public List InjuryOptions {
return injuryOptions;
}
}
+ public IEnumerable SelectableInjuryOptions {
+ get {
+ return injuryOptions.Where(o => o.Selectable);
+ }
+ }
public IEnumerable BodyPartsForInjury(InjuryOption option) {
if (option.ValidParts == null || option.ValidParts.Count == 0) {
return SkinCoveredBodyParts.Select((UniqueBodyPart p) => { return p.Record; });
diff --git a/Source/Page_PrepareCarefully.cs b/Source/Page_PrepareCarefully.cs
index 079ee1b..5472162 100644
--- a/Source/Page_PrepareCarefully.cs
+++ b/Source/Page_PrepareCarefully.cs
@@ -35,13 +35,13 @@ public override Vector2 InitialSize {
//Logger.Debug("Screen safe area: " + Screen.safeArea);
//Logger.Debug("UI scale: " + Prefs.UIScale);
- //Vector2 maxSize = new Vector2(Screen.safeArea.width / Prefs.UIScale, Screen.safeArea.height / Prefs.UIScale);
- //Vector2 minSize = Page.StandardSize / Prefs.UIScale;
+ Vector2 maxSize = new Vector2(Screen.safeArea.width / Prefs.UIScale, Screen.safeArea.height / Prefs.UIScale);
+ Vector2 minSize = Page.StandardSize / Prefs.UIScale;
- //Vector2 padding = new Vector2(64, 64) / Prefs.UIScale;
- //maxSize -= padding;
+ Vector2 padding = new Vector2(64, 64) / Prefs.UIScale;
+ maxSize -= padding;
- //Vector2 largeSize = new Vector2(1350, Page.StandardSize.y);
+ Vector2 largeSize = new Vector2(1350, Page.StandardSize.y);
//if (maxSize.x >= largeSize.x && maxSize.y >= largeSize.y) {
// LargeUI = true;
@@ -94,7 +94,8 @@ public Page_PrepareCarefully() {
currentTab.TabRecord = tabRecord;
tabRecords.Add(tabRecord);
}
-
+ State.CurrentTab = tabViewPawns;
+ tabViewPawns.TabRecord.selected = true;
}
override public void OnAcceptKeyPressed() {
@@ -140,9 +141,12 @@ public override void PreOpen() {
public override void DoWindowContents(Rect inRect) {
pawnListActionThisFrame = false;
base.DrawPageTitle(inRect);
- Rect mainRect = base.GetMainRect(inRect, 30f, false);
+ Rect mainRect = base.GetMainRect(inRect, 0, false).InsetBy(0, -6, 0, 0);
Widgets.DrawMenuSection(mainRect);
- TabDrawer.DrawTabs(mainRect, tabRecords);
+ float tabWidth = 180.0f;
+ float tabGroupWidth = tabRecords.Count * tabWidth;
+ float tabRectX = (mainRect.width * 0.5f) - (tabGroupWidth * 0.5f);
+ TabDrawer.DrawTabs(new Rect(tabRectX, mainRect.y, tabGroupWidth, mainRect.height), tabRecords, 180.0f);
// Determine the size of the tab view and draw the current tab.
Vector2 SizePageMargins = new Vector2(16, 16);
@@ -278,7 +282,7 @@ protected void DrawPoints(Rect parentRect) {
GUI.color = Style.ColorText;
label = "EdB.PC.Page.Points.Spent".Translate(points);
}
- Rect rect = new Rect(parentRect.width - costLabelWidth.Value, 2, costLabelWidth.Value, 32);
+ Rect rect = new Rect(parentRect.width - costLabelWidth.Value - 40, 4, costLabelWidth.Value, 32);
Widgets.Label(rect, label);
string tooltipText = "";
@@ -298,15 +302,20 @@ protected void DrawPoints(Rect parentRect) {
Text.Anchor = TextAnchor.UpperLeft;
Text.Font = GameFont.Small;
- string optionLabel;
- float optionTop = rect.y;
- optionLabel = "EdB.PC.Page.Points.UsePoints".Translate();
- Vector2 size = Text.CalcSize(optionLabel);
- Rect optionRect = new Rect(parentRect.width - costLabelWidth.Value - size.x - 100, optionTop, size.x + 10, 32);
- Widgets.Label(optionRect, optionLabel);
- GUI.color = Color.white;
- TooltipHandler.TipRegion(optionRect, "EdB.PC.Page.Points.UsePoints.Tip".Translate());
- Widgets.Checkbox(new Vector2(optionRect.x + optionRect.width, optionRect.y - 3), ref Config.pointsEnabled, 24, false);
+ if (WidgetDropdown.Button(new Rect(rect.xMax + 8, rect.yMin - 4, 31, 31), "", true, false, true)) {
+ List list = new List();
+ if (Config.pointsEnabled) {
+ list.Add(new FloatMenuOption("EdB.PC.Page.Points.DisablePoints".Translate(), () => {
+ Config.pointsEnabled = false;
+ }));
+ }
+ else {
+ list.Add(new FloatMenuOption("EdB.PC.Page.Points.UsePoints".Translate(), () => {
+ Config.pointsEnabled = true;
+ }));
+ }
+ Find.WindowStack.Add(new FloatMenu(list, null, false));
+ }
}
finally {
Text.Anchor = TextAnchor.UpperLeft;
@@ -365,7 +374,7 @@ protected void InstrumentPanels() {
};
tabViewPawns.PanelBackstory.BackstoryUpdated += pawnController.UpdateBackstory;
- tabViewPawns.PanelBackstory.BackstoryUpdated += (BackstorySlot slot, Backstory backstory) => { pawnController.CheckPawnCapabilities(); };
+ tabViewPawns.PanelBackstory.BackstoryUpdated += (BackstorySlot slot, BackstoryDef backstory) => { pawnController.CheckPawnCapabilities(); };
tabViewPawns.PanelBackstory.BackstoriesRandomized += pawnController.RandomizeBackstories;
tabViewPawns.PanelBackstory.BackstoriesRandomized += () => { pawnController.CheckPawnCapabilities(); };
@@ -409,6 +418,7 @@ protected void InstrumentPanels() {
};
pawnController.PawnAdded += (CustomPawn pawn) => { pawnController.CheckPawnCapabilities(); };
pawnController.PawnReplaced += (CustomPawn pawn) => { pawnController.CheckPawnCapabilities(); };
+ pawnController.PawnReplaced += (CustomPawn pawn) => { tabViewPawns.PanelAppearance.UpdatePawnLayers(); };
tabViewPawns.PanelHealth.InjuryAdded += pawnController.AddInjury;
tabViewPawns.PanelHealth.ImplantAdded += pawnController.AddImplant;
diff --git a/Source/PanelAge.cs b/Source/PanelAge.cs
index 09362dd..a58ed61 100644
--- a/Source/PanelAge.cs
+++ b/Source/PanelAge.cs
@@ -1,131 +1,201 @@
-using RimWorld;
+using EdB.PrepareCarefully.HarmonyPatches;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace EdB.PrepareCarefully {
- public class PanelAge : PanelBase {
- public delegate void UpdateAgeHandler(int age);
+ public class PanelAge : PanelModule {
+ public static readonly int DaysPerYear = 60;
+
+ public delegate void UpdateAgeHandler(int? ageYears, int? ageDays);
public event UpdateAgeHandler BiologicalAgeUpdated;
public event UpdateAgeHandler ChronologicalAgeUpdated;
private ProviderAgeLimits providerAgeLimits = PrepareCarefully.Instance.Providers.AgeLimits;
- protected static Rect RectBiologicalAgeLabel;
- protected static Rect RectBiologicalAgeField;
- protected static Rect RectChronologicalAgeLabel;
- protected static Rect RectChronologicalAgeField;
-
- private WidgetNumberField biologicalField;
- private WidgetNumberField chronologicalField;
+ protected Rect RectDevelopmentStageButton;
+ protected Rect RectBiologicalAgeLabel;
+ protected Rect RectBiologicalAgeFieldYears;
+ protected Rect RectBiologicalAgeFieldDays;
+ protected Rect RectChronologicalAgeLabel;
+ protected Rect RectChronologicalAgeFieldYears;
+ protected Rect RectChronologicalAgeFieldDays;
+ protected Rect RectYearsLabel;
+ protected Rect RectDaysLabel;
+ protected Rect RectDevelopmentalStageDropdown;
+ protected Rect RectHeader;
+
+ private WidgetNumberField biologicalFieldYears;
+ private WidgetNumberField biologicalFieldDays;
+ private WidgetNumberField chronologicalFieldYears;
+ private WidgetNumberField chronologicalFieldDays;
+ private AgeModifier ageModifier = new AgeModifier();
public PanelAge() {
- biologicalField = new WidgetNumberField() {
+ biologicalFieldYears = new WidgetNumberField() {
DragSlider = new DragSlider(0.4f, 20, 100),
- MinValue = 14,
+ MinValue = 0,
MaxValue = 99,
UpdateAction = (int value) => {
- UpdateBiologicalAge(value);
+ UpdateBiologicalAgeYears(value);
+ }
+ };
+ biologicalFieldDays = new WidgetNumberField() {
+ DragSlider = new DragSlider(0.4f, 15, 100),
+ MinValue = 0,
+ MaxValue = 59,
+ UpdateAction = (int value) => {
+ UpdateBiologicalAgeDays(value);
}
};
- chronologicalField = new WidgetNumberField() {
+ chronologicalFieldYears = new WidgetNumberField() {
DragSlider = new DragSlider(0.4f, 15, 100),
- MinValue = 14,
+ MinValue = 0,
MaxValue = Constraints.AgeChronologicalMax,
UpdateAction = (int value) => {
- UpdateChronologicalAge(value);
+ UpdateChronologicalAgeYears(value);
+ }
+ };
+ chronologicalFieldDays = new WidgetNumberField() {
+ DragSlider = new DragSlider(0.4f, 15, 100),
+ MinValue = 0,
+ MaxValue = 59,
+ UpdateAction = (int value) => {
+ UpdateChronologicalAgeDays(value);
}
};
}
- protected void UpdateBiologicalAge(int value) {
- BiologicalAgeUpdated(value);
+ protected void UpdateBiologicalAgeYears(int? value) {
+ BiologicalAgeUpdated(value, null);
+ }
+ protected void UpdateBiologicalAgeDays(int? value) {
+ BiologicalAgeUpdated(null, value);
}
- protected void UpdateChronologicalAge(int value) {
- ChronologicalAgeUpdated(value);
+ protected void UpdateChronologicalAgeYears(int? value) {
+ ChronologicalAgeUpdated(value, null);
+ }
+ protected void UpdateChronologicalAgeDays(int? value) {
+ ChronologicalAgeUpdated(null, value);
}
- public override void Resize(Rect rect) {
- base.Resize(rect);
+ public override void Resize(float width) {
+ base.Resize(width);
- Vector2 available = PanelRect.size - Style.SizePanelPadding;
+ float panelPadding = Style.SizePanelPadding.x;
+ float availableSize = width - panelPadding * 2;
+
+ GameFont saveFont = Text.Font;
+ Text.Font = GameFont.Small;
+ Vector2 bioLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Label.BiologicalAge".Translate());
+ Vector2 chronoLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Label.ChronologicalAge".Translate());
+ Text.Font = saveFont;
+ float minimumLabelWidth = Mathf.Max(bioLabelSize.x, chronoLabelSize.x);
float arrowPadding = 1;
float arrowWidth = Textures.TextureButtonNext.width;
- float bioWidth = 32;
- float chronoWidth = 48;
+ float widthNeededForArrowButtons = 4 * (arrowWidth + arrowPadding);
- float extendedArrowSize = arrowPadding + arrowWidth;
- float extendedFieldSize = extendedArrowSize * 2;
+ float paddingBetweenLabelAndField = 8;
+ float paddingBetweenFields = 8;
+ float fieldHeight = 24;
- float usedSpace = (extendedFieldSize * 2) + bioWidth + chronoWidth;
+ float widthNeededForFixedElements = minimumLabelWidth + paddingBetweenFields + paddingBetweenLabelAndField + widthNeededForArrowButtons;
+ float availableWidthForFields = availableSize - widthNeededForFixedElements;
- float availableSpace = PanelRect.width - usedSpace;
- float spacing = availableSpace / 3;
+ float yearFieldWidth = Mathf.Ceil(availableWidthForFields * 0.6f);
+ float dayFieldWidth = availableWidthForFields - yearFieldWidth;
- float idealSpace = 15;
- float extraFieldWidth = 0;
- if (spacing > idealSpace) {
- float extra = (spacing - idealSpace) * 3;
- extraFieldWidth += Mathf.Floor(extra / 2);
- spacing = idealSpace;
- }
- else {
- spacing = Mathf.Floor(spacing);
- }
- float fieldHeight = 28;
+ float yearFieldOffset = panelPadding + minimumLabelWidth + paddingBetweenLabelAndField + arrowPadding + arrowWidth;
+ float dayFieldOffset = yearFieldOffset + yearFieldWidth + paddingBetweenFields + arrowPadding * 2 + arrowWidth * 2;
- GameFont saveFont = Text.Font;
- Text.Font = GameFont.Tiny;
- Vector2 bioLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Biological".Translate());
- Vector2 chronoLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Chronological".Translate());
+ float developmentStageDropdownWidth = 30;
+ RectDevelopmentalStageDropdown = new Rect(width - developmentStageDropdownWidth - panelPadding, 0, developmentStageDropdownWidth, 30);
+
+ RectBiologicalAgeLabel = new Rect(panelPadding, 0, bioLabelSize.x, fieldHeight);
+ RectBiologicalAgeFieldYears = new Rect(yearFieldOffset, RectBiologicalAgeLabel.yMin, yearFieldWidth, fieldHeight);
+ RectBiologicalAgeFieldDays = new Rect(dayFieldOffset, RectBiologicalAgeLabel.yMin, dayFieldWidth, fieldHeight);
+
+ RectChronologicalAgeLabel = new Rect(panelPadding, 0, chronoLabelSize.x, fieldHeight);
+ RectChronologicalAgeFieldYears = new Rect(yearFieldOffset, RectChronologicalAgeLabel.yMin, yearFieldWidth, fieldHeight);
+ RectChronologicalAgeFieldDays = new Rect(dayFieldOffset, RectBiologicalAgeLabel.yMin, dayFieldWidth, fieldHeight);
+
+ saveFont = Text.Font;
+ Text.Font = GameFont.Small;
+ Vector2 yearsLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Label.Years".Translate());
+ Vector2 daysLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Label.Days".Translate());
Text.Font = saveFont;
- float labelHeight = Mathf.Max(bioLabelSize.y, chronoLabelSize.y);
- float contentHeight = labelHeight + fieldHeight;
- float top = PanelRect.HalfHeight() - (contentHeight * 0.5f);
- float fieldTop = top + labelHeight;
-
- RectBiologicalAgeField = new Rect(spacing + extendedArrowSize, fieldTop, bioWidth + extraFieldWidth, fieldHeight);
- RectChronologicalAgeField = new Rect(RectBiologicalAgeField.xMax + extendedArrowSize +
- spacing + extendedArrowSize, fieldTop, chronoWidth + extraFieldWidth, fieldHeight);
-
- RectBiologicalAgeLabel = new Rect(RectBiologicalAgeField.MiddleX() - bioLabelSize.x / 2,
- RectBiologicalAgeField.y - bioLabelSize.y, bioLabelSize.x, bioLabelSize.y);
- RectChronologicalAgeLabel = new Rect(RectChronologicalAgeField.MiddleX() - chronoLabelSize.x / 2,
- RectChronologicalAgeField.y - chronoLabelSize.y, chronoLabelSize.x, chronoLabelSize.y);
+ RectYearsLabel = new Rect(yearFieldOffset + yearFieldWidth * 0.5f - yearsLabelSize.x * 0.5f, 0, yearsLabelSize.x, yearsLabelSize.y);
+ RectDaysLabel = new Rect(dayFieldOffset + dayFieldWidth * 0.5f - daysLabelSize.x * 0.5f, 0, daysLabelSize.x, daysLabelSize.y);
}
- protected override void DrawPanelContent(State state) {
- base.DrawPanelContent(state);
+ public override float Draw(State state, float y) {
// Update field values.
- CustomPawn customPawn = state.CurrentPawn;
- int maxAge = providerAgeLimits.MaxAgeForPawn(customPawn.Pawn);
- int minAge = providerAgeLimits.MinAgeForPawn(customPawn.Pawn);
- chronologicalField.MinValue = customPawn.BiologicalAge;
- biologicalField.MinValue = minAge;
- biologicalField.MaxValue = customPawn.ChronologicalAge < maxAge ? customPawn.ChronologicalAge : maxAge;
-
- // Age labels.
+ CustomPawn pawn = state.CurrentPawn;
+ int maxAge = providerAgeLimits.MaxAgeForPawn(pawn.Pawn);
+ int minAge = providerAgeLimits.MinAgeForPawn(pawn.Pawn);
+ chronologicalFieldYears.MinValue = minAge;
+ biologicalFieldYears.MinValue = minAge;
+ biologicalFieldYears.MaxValue = maxAge;
+
+ float top = y;
+ y += Margin.y;
+
+ y += DrawHeader(y, Width, "EdB.PC.Panel.Age.Header".Translate().Resolve());
+ Rect rect;
+
Text.Font = GameFont.Tiny;
GUI.color = Style.ColorText;
- Widgets.Label(RectBiologicalAgeLabel, "EdB.PC.Panel.Age.Biological".Translate());
- Widgets.Label(RectChronologicalAgeLabel, "EdB.PC.Panel.Age.Chronological".Translate());
+ Text.Anchor = TextAnchor.MiddleCenter;
+ rect = RectYearsLabel.OffsetBy(0, y - RectYearsLabel.height);
+ Widgets.Label(rect, "EdB.PC.Panel.Age.Label.Years".Translate());
+ rect = RectDaysLabel.OffsetBy(0, y - RectDaysLabel.height);
+ Widgets.Label(rect, "EdB.PC.Panel.Age.Label.Days".Translate());
+
Text.Font = GameFont.Small;
- GUI.color = Color.white;
+ GUI.color = Style.ColorText;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ rect = RectBiologicalAgeLabel.OffsetBy(0, y);
+ Widgets.Label(rect, "EdB.PC.Panel.Age.Label.BiologicalAge".Translate());
+ // Biological age years field.
+ rect = RectBiologicalAgeFieldYears.OffsetBy(0, y);
+ biologicalFieldYears.Draw(rect, state.CurrentPawn.BiologicalAgeInYears);
+ // Biological age days field.
+ rect = RectBiologicalAgeFieldDays.OffsetBy(0, y);
+ biologicalFieldDays.Draw(rect, state.CurrentPawn.BiologicalAgeInDays % DaysPerYear);
+
+ y += RectBiologicalAgeLabel.height;
+
+ // Vertical padding between the two age field pairs
+ y += 6;
+
+ Text.Font = GameFont.Small;
+ GUI.color = Style.ColorText;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ rect = RectChronologicalAgeLabel.OffsetBy(0, y);
+ Widgets.Label(rect, "EdB.PC.Panel.Age.Label.ChronologicalAge".Translate());
+ // Chronological age years field.
+ rect = RectChronologicalAgeFieldYears.OffsetBy(0, y);
+ chronologicalFieldYears.Draw(rect, state.CurrentPawn.ChronologicalAgeInYears);
+ // Chronological age days field.
+ rect = RectChronologicalAgeFieldDays.OffsetBy(0, y);
+ chronologicalFieldDays.Draw(rect, state.CurrentPawn.ChronologicalAgeInDays % DaysPerYear);
+
+ y += RectChronologicalAgeLabel.height;
- // Biological age field.
- Rect fieldRect = RectBiologicalAgeField;
- biologicalField.Draw(fieldRect, customPawn.BiologicalAge);
+ Text.Font = GameFont.Small;
+ GUI.color = Color.white;
+ Text.Anchor = TextAnchor.UpperLeft;
- // Chronological age field.
- fieldRect = RectChronologicalAgeField;
- chronologicalField.Draw(fieldRect, customPawn.ChronologicalAge);
+ return y - top;
}
}
}
diff --git a/Source/PanelAppearance.cs b/Source/PanelAppearance.cs
index 4a3d0eb..ae9a08b 100644
--- a/Source/PanelAppearance.cs
+++ b/Source/PanelAppearance.cs
@@ -1,3 +1,4 @@
+using EdB.PrepareCarefully.Reflection;
using RimWorld;
using System;
using System.Collections.Generic;
@@ -106,10 +107,8 @@ public PanelAppearance() {
}
// Set up default skin colors
- foreach (Color color in PawnColorUtils.Colors) {
- skinColors.Add(color);
- }
-
+ skinColors = SkinColorsForPawn(null);
+
this.ChangePawnLayer(null);
}
@@ -117,6 +116,16 @@ public PanelAppearance() {
private Rect RectPortrait;
private Rect RectButtonRandomize;
+ public List SkinColorsForPawn(Verse.Pawn pawn) {
+ List result = new List();
+ result.AddRange(RimWorld.PawnSkinColors.SkinColorGenesInOrder.ConvertAll(gene => RimWorld.PawnSkinColors.GetSkinColor(gene.minMelanin)));
+ if (pawn == null) {
+ return result;
+ }
+ result.AddRange(pawn.genes.GenesListForReading.Where(g => g.def.skinColorOverride.HasValue).Select(g => g.def.skinColorOverride.Value));
+ return result;
+ }
+
public override void Resize(Rect rect) {
base.Resize(rect);
@@ -133,7 +142,11 @@ public override void Resize(Rect rect) {
RectGenderMale = new Rect(RectGenderFemale.xMax + 2, RectPortrait.y + 6, 20, 24);
}
- public void ChangePawn(CustomPawn pawn) {
+ protected List currentPawnLayers = null;
+ public void UpdatePawnLayers() {
+ var pawn = PrepareCarefully.Instance.State.CurrentPawn;
+ currentPawnLayers = PrepareCarefully.Instance.Providers.PawnLayers.GetLayersForPawn(pawn);
+
// Make sure the selected layer is still valid for the new pawn.
List layers = PrepareCarefully.Instance.Providers.PawnLayers.GetLayersForPawn(pawn);
if (selectedPawnLayer != null) {
@@ -141,47 +154,22 @@ public void ChangePawn(CustomPawn pawn) {
}
if (selectedPawnLayer == null) {
selectedPawnLayer = layers.FirstOrDefault();
+ selectedPawnLayer = layers.FirstOrDefault();
}
- // Prepare the delegate actions for the layer selected dropdown.
pawnLayerActions.Clear();
- foreach (var layer in layers) {
+ foreach (var layer in currentPawnLayers) {
pawnLayerActions.Add(delegate { this.ChangePawnLayer(layer); });
}
-
- currentPawn = pawn;
- }
-
- protected List currentPawnLayers = null;
- public void UpdatePawnLayers() {
- var pawn = PrepareCarefully.Instance.State.CurrentPawn;
- currentPawnLayers = PrepareCarefully.Instance.Providers.PawnLayers.GetLayersForPawn(pawn);
- if (selectedPawnLayer != null) {
- foreach (var layer in currentPawnLayers) {
- if (layer.Name == selectedPawnLayer.Name) {
- selectedPawnLayer = layer;
- /*
- if (layer.Options != null) {
- bool found = false;
- foreach (var option in layer.Options) {
- if (layer.IsOptionSelected(pawn, option)) {
- found = true;
- break;
- }
- }
- }
- */
- break;
- }
- }
- }
+ skinColors = SkinColorsForPawn(PrepareCarefully.Instance.State.CurrentPawn.Pawn);
}
protected override void DrawPanelContent(State state) {
base.DrawPanelContent(state);
CustomPawn customPawn = state.CurrentPawn;
if (currentPawn != state.CurrentPawn) {
- ChangePawn(state.CurrentPawn);
+ UpdatePawnLayers();
+ currentPawn = state.CurrentPawn;
}
if (currentPawnLayers == null) {
UpdatePawnLayers();
@@ -189,7 +177,6 @@ protected override void DrawPanelContent(State state) {
string label = this.selectedPawnLayer.Label;
if (WidgetDropdown.Button(RectLayerSelector, label, true, false, true)) {
List list = new List();
- int layerCount = this.pawnLayerActions.Count;
int i = 0;
foreach (var layer in currentPawnLayers) {
label = layer.Label;
@@ -340,11 +327,11 @@ protected override void DrawPanelContent(State state) {
}
else if (selectedPawnLayer.ColorSelectorType == ColorSelectorType.Skin) {
AlienRace alienRace = customPawn.AlienRace;
- if (alienRace == null || alienRace.UseMelaninLevels) {
- DrawHumanlikeColorSelector(customPawn, cursorY);
+ if (alienRace == null || alienRace.UseMelaninLevels || alienRace.ThingDef?.defName == "Human") {
+ DrawSkinColorSelector(customPawn, cursorY, skinColors, true);
}
else if (alienRace.ChangeableColor) {
- DrawAlienPawnColorSelector(customPawn, cursorY, alienRace.PrimaryColors, true);
+ DrawSkinColorSelector(customPawn, cursorY, alienRace.PrimaryColors, true);
}
}
@@ -391,8 +378,14 @@ protected void DrawPawn(CustomPawn customPawn, Rect rect) {
try {
Vector2 pawnSize = new Vector2(128f, 180f);
Rect pawnRect = new Rect(rect.width * 0.5f - pawnSize.x * 0.5f, 10 + rect.height * 0.5f - pawnSize.y * 0.5f, pawnSize.x, pawnSize.y);
+
RenderTexture texture = customPawn.GetPortrait(pawnSize);
- GUI.DrawTexture(pawnRect, (Texture)texture);
+ if (texture != null) {
+ GUI.DrawTexture(pawnRect, (Texture)texture);
+ }
+ }
+ catch (Exception e) {
+ Logger.Error("Failed to draw pawn", e);
}
finally {
GUI.EndGroup();
@@ -582,7 +575,7 @@ protected void DrawColorSelectorForPawnLayer(CustomPawn customPawn, float cursor
GUI.color = Color.white;
}
- protected void DrawAlienPawnColorSelector(CustomPawn customPawn, float cursorY, List colors, bool allowAnyColor) {
+ protected void DrawSkinColorSelector(CustomPawn customPawn, float cursorY, List colors, bool allowAnyColor) {
Color currentColor = customPawn.Pawn.story.SkinColor;
Color clickedColor = currentColor;
Rect rect = new Rect(SwatchPosition.x, cursorY, SwatchSize.x, SwatchSize.y);
@@ -666,97 +659,6 @@ protected void SetColor(CustomPawn customPawn, Color color) {
customPawn.SetColor(selectedPawnLayer, color);
}
- protected void DrawHumanlikeColorSelector(CustomPawn customPawn, float cursorY) {
- float melanin = customPawn.MelaninLevel;
- int currentSwatchIndex = PawnColorUtils.GetLeftIndexForValue(melanin);
- Color currentSwatchColor = PawnColorUtils.Colors[currentSwatchIndex];
-
- Rect swatchRect = new Rect(SwatchPosition.x, cursorY, SwatchSize.x, SwatchSize.y);
-
- // Draw the swatch selection boxes.
- int colorCount = PawnColorUtils.Colors.Length - 1;
- int clickedIndex = -1;
- for (int i = 0; i < colorCount; i++) {
- Color color = PawnColorUtils.Colors[i];
-
- // If the swatch is selected, draw a heavier border around it.
- bool isThisSwatchSelected = (i == currentSwatchIndex);
- if (isThisSwatchSelected) {
- Rect selectionRect = new Rect(swatchRect.x - 2, swatchRect.y - 2, SwatchSize.x + 4, SwatchSize.y + 4);
- GUI.color = ColorSwatchSelection;
- GUI.DrawTexture(selectionRect, BaseContent.WhiteTex);
- }
-
- // Draw the border around the swatch.
- Rect borderRect = new Rect(swatchRect.x - 1, swatchRect.y - 1, SwatchSize.x + 2, SwatchSize.y + 2);
- GUI.color = ColorSwatchBorder;
- GUI.DrawTexture(borderRect, BaseContent.WhiteTex);
-
- // Draw the swatch itself.
- GUI.color = color;
- GUI.DrawTexture(swatchRect, BaseContent.WhiteTex);
-
- if (!isThisSwatchSelected) {
- if (Widgets.ButtonInvisible(swatchRect, false)) {
- clickedIndex = i;
- //currentSwatchColor = color;
- }
- }
-
- // Advance the swatch rect cursor position and wrap it if necessary.
- swatchRect.x += SwatchSpacing.x;
- if (swatchRect.x >= SwatchLimit - SwatchSize.x) {
- swatchRect.y += SwatchSpacing.y;
- swatchRect.x = SwatchPosition.x;
- }
- }
-
- // Draw the current color box.
- GUI.color = Color.white;
- Rect currentColorRect = new Rect(SwatchPosition.x, swatchRect.y + 4, 49, 49);
- if (swatchRect.x != SwatchPosition.x) {
- currentColorRect.y += SwatchSpacing.y;
- }
- GUI.color = ColorSwatchBorder;
- GUI.DrawTexture(currentColorRect, BaseContent.WhiteTex);
- GUI.color = customPawn.SkinColor;
- GUI.DrawTexture(currentColorRect.ContractedBy(1), BaseContent.WhiteTex);
- GUI.color = Color.white;
-
- // Figure out the lerp value so that we can draw the slider.
- float minValue = 0.00f;
- float maxValue = 0.99f;
- float t = PawnColorUtils.GetRelativeLerpValue(customPawn.MelaninLevel);
- if (t < minValue) {
- t = minValue;
- }
- else if (t > maxValue) {
- t = maxValue;
- }
- if (clickedIndex != -1) {
- t = minValue;
- }
-
- // Draw the slider.
- float newValue = GUI.HorizontalSlider(new Rect(currentColorRect.x + 56, currentColorRect.y + 18, 136, 16), t, minValue, 1);
- if (newValue < minValue) {
- newValue = minValue;
- }
- else if (newValue > maxValue) {
- newValue = maxValue;
- }
- GUI.color = Color.white;
-
- // If the user selected a new swatch or changed the lerp value, set a new color value.
- if (t != newValue || clickedIndex != -1) {
- if (clickedIndex != -1) {
- currentSwatchIndex = clickedIndex;
- }
- float melaninLevel = PawnColorUtils.GetValueFromRelativeLerp(currentSwatchIndex, newValue);
- customPawn.MelaninLevel = melaninLevel;
- }
- }
-
protected void DrawFieldSelector(Rect fieldRect, string label, Action previousAction, Action nextAction, Action clickAction) {
DrawFieldSelector(fieldRect, label, previousAction, nextAction, clickAction, Style.ColorText);
}
@@ -814,14 +716,6 @@ protected string PawnLayerLabel {
get {
CustomPawn customPawn = PrepareCarefully.Instance.State.CurrentPawn;
string label = "EdB.PC.Panel.Appearance.NoneSelected".Translate();
- /*
- if (selectedPawnLayer == PrepareCarefully.Instance.Providers.PawnLayers.BodyLayer) {
- label = PrepareCarefully.Instance.Providers.BodyTypes.GetBodyTypeLabel(customPawn.BodyType);
- }
- else if (selectedPawnLayer == PrepareCarefully.Instance.Providers.PawnLayers.HeadLayer) {
- label = GetHeadLabel(customPawn);
- }
- */
if (selectedPawnLayer.Options != null) {
PawnLayerOption option = selectedPawnLayer.GetSelectedOption(customPawn);
if (option != null) {
@@ -846,7 +740,7 @@ protected string PawnLayerLabel {
}
protected void SelectNextHead(CustomPawn customPawn, int direction) {
- List heads = PrepareCarefully.Instance.Providers.HeadTypes.GetHeadTypes(customPawn.Pawn.def, customPawn.Gender).ToList();
+ List heads = PrepareCarefully.Instance.Providers.HeadTypes.GetHeadTypes(customPawn.Pawn.def, customPawn.Gender).ToList();
int index = heads.IndexOf(customPawn.HeadType);
if (index == -1) {
return;
@@ -862,9 +756,13 @@ protected void SelectNextHead(CustomPawn customPawn, int direction) {
this.pawnLayerLabel = GetHeadLabel(customPawn);
}
- protected void SelectNextBodyType(CustomPawn customPawn, int direction) {
+ protected List BodyTypesForPawn(CustomPawn pawn) {
ProviderBodyTypes provider = PrepareCarefully.Instance.Providers.BodyTypes;
- List bodyTypes = provider.GetBodyTypesForPawn(customPawn);
+ return provider.GetBodyTypesForPawn(pawn).Where(b => b != BodyTypeDefOf.Baby && b != BodyTypeDefOf.Child).ToList();
+ }
+
+ protected void SelectNextBodyType(CustomPawn customPawn, int direction) {
+ List bodyTypes = BodyTypesForPawn(customPawn);
int index = bodyTypes.IndexOf(customPawn.BodyType);
if (index == -1) {
Logger.Warning("Could not find the current pawn's body type in list of available options: " + customPawn.BodyType);
@@ -878,6 +776,7 @@ protected void SelectNextBodyType(CustomPawn customPawn, int direction) {
index = 0;
}
customPawn.BodyType = bodyTypes[index];
+ ProviderBodyTypes provider = PrepareCarefully.Instance.Providers.BodyTypes;
this.pawnLayerLabel = provider.GetBodyTypeLabel(customPawn.BodyType);
}
@@ -932,7 +831,7 @@ protected void SelectNextPawnLayerOption(CustomPawn customPawn, int direction) {
protected string GetHeadLabel(CustomPawn pawn) {
if (pawn.HeadType != null) {
- return pawn.HeadType.Label;
+ return pawn.HeadType.LabelCap;
}
else {
return "EdB.PC.Common.Default".Translate();
diff --git a/Source/PanelBackstory.cs b/Source/PanelBackstory.cs
index 9e3c7b2..f635d23 100644
--- a/Source/PanelBackstory.cs
+++ b/Source/PanelBackstory.cs
@@ -15,10 +15,10 @@ public class PanelBackstory : PanelModule {
protected Field FieldChildhood = new Field();
protected Field FieldAdulthood = new Field();
protected ProviderBackstories providerBackstories = PrepareCarefully.Instance.Providers.Backstories;
- protected List> availableFilters = new List>();
- protected List> activeFilters = new List>();
+ protected List> availableFilters = new List>();
+ protected List> activeFilters = new List>();
- public delegate void UpdateBackstoryHandler(BackstorySlot slot, Backstory backstory);
+ public delegate void UpdateBackstoryHandler(BackstorySlot slot, BackstoryDef backstory);
public delegate void RandomizeBackstoriesHandler();
public event UpdateBackstoryHandler BackstoryUpdated;
@@ -74,15 +74,25 @@ protected float DrawChildhood(CustomPawn pawn, float y, float width) {
FieldChildhood.Label = null;
}
FieldChildhood.Tip = pawn.Childhood.CheckedDescriptionFor(pawn.Pawn);
- FieldChildhood.ClickAction = () => {
- ShowBackstoryDialog(pawn, BackstorySlot.Childhood);
- };
- FieldChildhood.PreviousAction = () => {
- NextBackstory(pawn, BackstorySlot.Childhood, -1);
- };
- FieldChildhood.NextAction = () => {
- NextBackstory(pawn, BackstorySlot.Childhood, 1);
- };
+ if (pawn.IsNewborn() || pawn.IsJuvenile()) {
+ FieldChildhood.ClickAction = null;
+ FieldChildhood.PreviousAction = null;
+ FieldChildhood.NextAction = null;
+ FieldChildhood.NextPreviousButtonsHidden = true;
+ }
+ else {
+ FieldChildhood.NextPreviousButtonsHidden = false;
+ FieldChildhood.ClickAction = () => {
+ ShowBackstoryDialog(pawn, BackstorySlot.Childhood);
+ };
+ FieldChildhood.PreviousAction = () => {
+ NextBackstory(pawn, BackstorySlot.Childhood, -1);
+ };
+ FieldChildhood.NextAction = () => {
+ NextBackstory(pawn, BackstorySlot.Childhood, 1);
+ };
+ }
+
FieldChildhood.Draw();
return FieldRect.height;
@@ -157,7 +167,9 @@ public override float Draw(State state, float y) {
y += Margin.y;
CustomPawn pawn = state.CurrentPawn;
- DrawRandomizeButton(y, Width);
+ if (pawn.Pawn.DevelopmentalStage == DevelopmentalStage.Adult) {
+ DrawRandomizeButton(y, Width);
+ }
y += DrawHeader(y, Width, "Backstory".Translate().Resolve());
y += DrawChildhood(pawn, y, Width);
y += 6;
@@ -178,24 +190,24 @@ public override float Draw(State state, float y) {
}
protected void ShowBackstoryDialog(CustomPawn customPawn, BackstorySlot slot) {
- Backstory originalBackstory = (slot == BackstorySlot.Childhood) ? customPawn.Childhood : customPawn.Adulthood;
- Backstory selectedBackstory = originalBackstory;
- Filter filterToRemove = null;
+ BackstoryDef originalBackstory = (slot == BackstorySlot.Childhood) ? customPawn.Childhood : customPawn.Adulthood;
+ BackstoryDef selectedBackstory = originalBackstory;
+ Filter filterToRemove = null;
bool filterListDirtyFlag = true;
- List fullOptionsList = slot == BackstorySlot.Childhood ?
+ List fullOptionsList = slot == BackstorySlot.Childhood ?
this.providerBackstories.AllChildhookBackstories : this.providerBackstories.AllAdulthookBackstories;
- List filteredBackstories = new List(fullOptionsList.Count);
- Dialog_Options dialog = new Dialog_Options(filteredBackstories) {
- NameFunc = (Backstory backstory) => {
+ List filteredBackstories = new List(fullOptionsList.Count);
+ Dialog_Options dialog = new Dialog_Options(filteredBackstories) {
+ NameFunc = (BackstoryDef backstory) => {
return backstory.TitleCapFor(customPawn.Gender);
},
- DescriptionFunc = (Backstory backstory) => {
+ DescriptionFunc = (BackstoryDef backstory) => {
return backstory.CheckedDescriptionFor(customPawn.Pawn);
},
- SelectedFunc = (Backstory backstory) => {
+ SelectedFunc = (BackstoryDef backstory) => {
return selectedBackstory == backstory;
},
- SelectAction = (Backstory backstory) => {
+ SelectAction = (BackstoryDef backstory) => {
selectedBackstory = backstory;
},
CloseAction = () => {
@@ -294,8 +306,8 @@ protected void ShowBackstoryDialog(CustomPawn customPawn, BackstorySlot slot) {
}
protected void NextBackstory(CustomPawn pawn, BackstorySlot slot, int direction) {
- Backstory backstory;
- List backstories;
+ BackstoryDef backstory;
+ List backstories;
PopulateBackstoriesFromSlot(pawn, slot, out backstories, out backstory);
int currentIndex = FindBackstoryIndex(pawn, slot);
@@ -310,14 +322,14 @@ protected void NextBackstory(CustomPawn pawn, BackstorySlot slot, int direction)
}
protected int FindBackstoryIndex(CustomPawn pawn, BackstorySlot slot) {
- Backstory backstory;
- List backstories;
+ BackstoryDef backstory;
+ List backstories;
PopulateBackstoriesFromSlot(pawn, slot, out backstories, out backstory);
return backstories.IndexOf(backstory);
}
- protected void PopulateBackstoriesFromSlot(CustomPawn pawn, BackstorySlot slot, out List backstories,
- out Backstory backstory) {
+ protected void PopulateBackstoriesFromSlot(CustomPawn pawn, BackstorySlot slot, out List backstories,
+ out BackstoryDef backstory) {
backstory = (slot == BackstorySlot.Childhood) ? pawn.Childhood : pawn.Adulthood;
backstories = (slot == BackstorySlot.Childhood) ? providerBackstories.GetChildhoodBackstoriesForPawn(pawn)
: providerBackstories.GetAdulthoodBackstoriesForPawn(pawn);
diff --git a/Source/PanelFavoriteColor.cs b/Source/PanelFavoriteColor.cs
index 54fccd9..29ff7b7 100644
--- a/Source/PanelFavoriteColor.cs
+++ b/Source/PanelFavoriteColor.cs
@@ -6,6 +6,8 @@
using UnityEngine;
using Verse;
using Verse.Sound;
+using static UnityEngine.Random;
+
namespace EdB.PrepareCarefully {
public class PanelFavoriteColor : PanelBase {
public delegate void UpdateFavoriteColorHandler(Color? color);
@@ -26,7 +28,13 @@ public override void Resize(Rect rect) {
protected override void DrawPanelContent(State state) {
base.DrawPanelContent(state);
+ if (state.CurrentPawn.Pawn.DevelopmentalStage.Baby()) {
+ DrawForBaby();
+ return;
+ }
+
Rect rect = new Rect(8, 8, PanelRect.width - 16, PanelRect.height - 16);
+
Color favoriteColor = state.CurrentPawn.Pawn.story.favoriteColor.HasValue ? state.CurrentPawn.Pawn.story.favoriteColor.Value : new Color(0.5f, 0.5f, 0.5f);
if (rect.Contains(Event.current.mousePosition)) {
@@ -44,6 +52,22 @@ protected override void DrawPanelContent(State state) {
Find.WindowStack.Add(dialog);
}
+ Text.Font = GameFont.Small;
+ GUI.color = Color.white;
+ Text.Anchor = TextAnchor.UpperLeft;
+ }
+ protected void DrawForBaby() {
+ Rect rect = new Rect(8, 8, PanelRect.width - 16, PanelRect.height - 16);
+
+ //if (rect.Contains(Event.current.mousePosition)) {
+ // GUI.DrawTexture(rect, BaseContent.WhiteTex);
+ // GUI.color = Color.white;
+ //}
+
+ GUI.color = Style.ColorTabViewBackground;
+ Widgets.DrawBox(rect, 2);
+ Widgets.DrawLine(new Vector2(rect.xMin, rect.yMin), new Vector2(rect.xMax, rect.yMax), GUI.color, 2);
+
Text.Font = GameFont.Small;
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
diff --git a/Source/PanelHealth.cs b/Source/PanelHealth.cs
index 820b8c7..eb23752 100644
--- a/Source/PanelHealth.cs
+++ b/Source/PanelHealth.cs
@@ -292,11 +292,12 @@ public void DrawAddButton(float y, float width) {
}
};
- injuryOptionDialog = new Dialog_Options(healthOptions.InjuryOptions) {
+ injuryOptionDialog = new Dialog_Options(healthOptions.SelectableInjuryOptions) {
ConfirmButtonLabel = "EdB.PC.Common.Next".Translate(),
CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(),
HeaderLabel = "EdB.PC.Dialog.Injury.Header".Translate(),
NameFunc = (InjuryOption option) => {
+ //return option.HediffDef.defName;
return option.Label;
},
DescriptionFunc = (InjuryOption option) => {
diff --git a/Source/PanelIdeo.cs b/Source/PanelIdeo.cs
index ae99a88..c93fee5 100644
--- a/Source/PanelIdeo.cs
+++ b/Source/PanelIdeo.cs
@@ -45,7 +45,7 @@ public float Measure() {
}
public override bool IsVisible(State state) {
- return ModsConfig.IdeologyActive;
+ return ModsConfig.IdeologyActive && !state.CurrentPawn.Pawn.DevelopmentalStage.Baby();
}
public override float Draw(State state, float y) {
@@ -73,7 +73,9 @@ public override float Draw(State state, float y) {
Find.WindowStack.Add(dialog);
};
FieldIdeo.DrawIconFunc = (Rect rect) => {
- ideo.DrawIcon(rect);
+ if (ideo != null) {
+ ideo.DrawIcon(rect);
+ }
};
FieldIdeo.IconSizeFunc = () => new Vector2(32, 32);
diff --git a/Source/PanelModule.cs b/Source/PanelModule.cs
index 213d851..cfb1c76 100644
--- a/Source/PanelModule.cs
+++ b/Source/PanelModule.cs
@@ -35,7 +35,12 @@ public virtual float Draw(State state, float y) {
}
public virtual float DrawHeader(float y, float width, string text) {
- Rect headerLabelRect = new Rect(Margin.x, y, width - (Margin.x * 2), HeaderHeight);
+ DrawHeaderWithOffset(0, y, width, text);
+ return HeaderHeight;
+ }
+
+ public virtual float DrawHeaderWithOffset(float offset, float y, float width, string text) {
+ Rect headerLabelRect = new Rect(Margin.x + offset, y, width - (Margin.x * 2) - offset, HeaderHeight);
var fontValue = Text.Font;
var anchorValue = Text.Anchor;
var colorValue = GUI.color;
diff --git a/Source/PanelModuleAge.cs b/Source/PanelModuleAge.cs
deleted file mode 100644
index 38c603f..0000000
--- a/Source/PanelModuleAge.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using UnityEngine;
-using RimWorld;
-using Verse;
-using Verse.Sound;
-
-namespace EdB.PrepareCarefully {
- public class PanelModuleAge : PanelModule {
- public static readonly Vector2 FieldPadding = new Vector2(6, 6);
- public delegate void UpdateAgeHandler(int age);
-
- public event UpdateAgeHandler BiologicalAgeUpdated;
- public event UpdateAgeHandler ChronologicalAgeUpdated;
-
- private ProviderAgeLimits providerAgeLimits = PrepareCarefully.Instance.Providers.AgeLimits;
-
- protected static Rect RectBiologicalAgeLabel;
- protected static Rect RectBiologicalAgeField;
- protected static Rect RectChronologicalAgeLabel;
- protected static Rect RectChronologicalAgeField;
-
- private WidgetNumberField biologicalField;
- private WidgetNumberField chronologicalField;
-
- public PanelModuleAge() {
- biologicalField = new WidgetNumberField() {
- DragSlider = new DragSlider(0.4f, 20, 100),
- MinValue = 14,
- MaxValue = 99,
- UpdateAction = (int value) => {
- UpdateBiologicalAge(value);
- }
- };
- chronologicalField = new WidgetNumberField() {
- DragSlider = new DragSlider(0.4f, 15, 100),
- MinValue = 14,
- MaxValue = Constraints.AgeChronologicalMax,
- UpdateAction = (int value) => {
- UpdateChronologicalAge(value);
- }
- };
- }
-
- protected void UpdateBiologicalAge(int value) {
- BiologicalAgeUpdated(value);
- }
-
- protected void UpdateChronologicalAge(int value) {
- ChronologicalAgeUpdated(value);
- }
-
- public override void Resize(float width) {
- base.Resize(width);
-
- float arrowPadding = 1;
- float arrowWidth = Textures.TextureButtonNext.width;
- float bioWidth = 32;
- float chronoWidth = 48;
-
- float extendedArrowSize = arrowPadding + arrowWidth;
- float extendedFieldSize = extendedArrowSize * 2;
-
- float usedSpace = (extendedFieldSize * 2) + bioWidth + chronoWidth;
-
- float availableSpace = width - usedSpace;
- float spacing = availableSpace / 3;
-
- float idealSpace = 15;
- float extraFieldWidth = 0;
- if (spacing > idealSpace) {
- float extra = (spacing - idealSpace) * 3;
- extraFieldWidth += Mathf.Floor(extra / 2);
- spacing = idealSpace;
- }
- else {
- spacing = Mathf.Floor(spacing);
- }
- float fieldHeight = 28;
-
- GameFont saveFont = Text.Font;
- Text.Font = GameFont.Tiny;
- Vector2 bioLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Biological".Translate());
- Vector2 chronoLabelSize = Text.CalcSize("EdB.PC.Panel.Age.Chronological".Translate());
- Text.Font = saveFont;
-
- float labelHeight = Mathf.Max(bioLabelSize.y, chronoLabelSize.y);
- float top = 0;
- float fieldTop = top + labelHeight;
-
- RectBiologicalAgeField = new Rect(spacing + extendedArrowSize, fieldTop, bioWidth + extraFieldWidth, fieldHeight);
- RectChronologicalAgeField = new Rect(RectBiologicalAgeField.xMax + extendedArrowSize +
- spacing + extendedArrowSize, fieldTop, chronoWidth + extraFieldWidth, fieldHeight);
-
- RectBiologicalAgeLabel = new Rect(RectBiologicalAgeField.MiddleX() - bioLabelSize.x / 2,
- RectBiologicalAgeField.y - bioLabelSize.y, bioLabelSize.x, bioLabelSize.y);
- RectChronologicalAgeLabel = new Rect(RectChronologicalAgeField.MiddleX() - chronoLabelSize.x / 2,
- RectChronologicalAgeField.y - chronoLabelSize.y, chronoLabelSize.x, chronoLabelSize.y);
- }
-
- public float Measure() {
- return 0;
- }
-
- public override bool IsVisible(State state) {
- return base.IsVisible(state);
- }
-
- public override float Draw(State state, float y) {
- float top = y;
- y += Margin.y;
-
- // Update field values.
- CustomPawn pawn = state.CurrentPawn;
- int maxAge = providerAgeLimits.MaxAgeForPawn(pawn.Pawn);
- int minAge = providerAgeLimits.MinAgeForPawn(pawn.Pawn);
- chronologicalField.MinValue = pawn.BiologicalAge;
- biologicalField.MinValue = minAge;
- biologicalField.MaxValue = pawn.ChronologicalAge < maxAge ? pawn.ChronologicalAge : maxAge;
-
- // Age labels.
- Text.Font = GameFont.Tiny;
- GUI.color = Style.ColorText;
- Widgets.Label(RectBiologicalAgeLabel.OffsetBy(0, y), "EdB.PC.Panel.Age.Biological".Translate());
- Widgets.Label(RectChronologicalAgeLabel.OffsetBy(0, y), "EdB.PC.Panel.Age.Chronological".Translate());
- Text.Font = GameFont.Small;
- GUI.color = Color.white;
-
- // Biological age field.
- Rect fieldRect = RectBiologicalAgeField;
- biologicalField.Draw(fieldRect.OffsetBy(0, y), pawn.BiologicalAge);
-
- // Chronological age field.
- fieldRect = RectChronologicalAgeField;
- chronologicalField.Draw(fieldRect.OffsetBy(0, y), pawn.ChronologicalAge);
-
- y += RectBiologicalAgeLabel.height;
- y += fieldRect.height;
-
- y += Margin.y;
- return y - top;
- }
- }
-}
diff --git a/Source/PanelPawnList.cs b/Source/PanelPawnList.cs
index a3df88c..2973b50 100644
--- a/Source/PanelPawnList.cs
+++ b/Source/PanelPawnList.cs
@@ -14,7 +14,7 @@ public abstract class PanelPawnList : PanelBase {
public delegate void MinimizeHandler();
public delegate void AddPawnHandler(bool startingPawn);
public delegate void AddFactionPawnHandler(FactionDef def, bool startingPawn);
- public delegate void AddPawnWithPawnKindHandler(PawnKindDef def, bool startingPawn);
+ public delegate void AddPawnWithPawnKindHandler(PawnKindOption def, bool startingPawn);
public delegate void LoadCharacterHandler(string name);
public event SelectPawnHandler PawnSelected;
@@ -242,12 +242,16 @@ protected override void DrawPanelContent(State state) {
Rect pawnRect = RectPortrait.OffsetBy(rect.position);
GUI.color = Color.white;
- RenderTexture pawnTexture = pawn.GetPortrait(pawnRect.size);
+
Rect clipRect = RectEntry.OffsetBy(rect.position);
+ RenderTexture pawnTexture = pawn.GetPortrait(pawnRect.size);
try {
GUI.BeginClip(clipRect);
GUI.DrawTexture(RectPortrait, (Texture)pawnTexture);
}
+ catch (Exception e) {
+ Logger.Error("Failed to draw pawn", e);
+ }
finally {
GUI.EndClip();
}
@@ -268,11 +272,11 @@ protected override void DrawPanelContent(State state) {
string description = null;
if (pawn.IsAdult) {
if (pawn.Adulthood != null) {
- description = pawn.Adulthood.TitleShortCapFor(pawn.Gender);
+ description = pawn.Adulthood.TitleShortFor(pawn.Gender).CapitalizeFirst();
}
}
else {
- description = pawn.Childhood.TitleShortCapFor(pawn.Gender);
+ description = pawn.Childhood.TitleShortFor(pawn.Gender).CapitalizeFirst();
}
if (!description.NullOrEmpty()) {
Widgets.Label(professionRect, descriptionTrimmer.TrimLabelIfNeeded(description));
@@ -383,12 +387,12 @@ public IEnumerable AllPawnKinds(PawnKindDef basicKind, IEnumerable<
}
}
- protected List.RowGroup> rowGroups = new List.RowGroup>();
+ protected List.RowGroup> rowGroups = new List.RowGroup>();
protected void ShowPawnKindDialog() {
- HashSet disabled = new HashSet();
+ var disabled = new HashSet();
rowGroups.Clear();
- PawnKindDef selected = PrepareCarefully.Instance.State.LastSelectedPawnKindDef;
+ PawnKindOption selected = PrepareCarefully.Instance.State.LastSelectedPawnKindDef;
List factionPawnKindsList = new List(PrepareCarefully.Instance.Providers.PawnKinds.PawnKindsByFaction);
// Sort the pawn kinds to put the colony faction at the top.
@@ -407,21 +411,26 @@ protected void ShowPawnKindDialog() {
// If no pawn kind has been selected, select the colony's basic pawn kind by default.
if (selected == null) {
- selected = factionPawnKindsList?.FirstOrDefault(f => f != null)?.PawnKinds?.FirstOrDefault(k => k != null);
+ var faction = factionPawnKindsList?.FirstOrDefault(f => f != null)?.Faction;
+ var kind = factionPawnKindsList?.FirstOrDefault(f => f != null)?.PawnKinds?.FirstOrDefault(k => k != null);
+ if (faction != null && kind != null) {
+ selected = new PawnKindOption(faction, kind);
+ }
}
foreach (var factionPawnKinds in factionPawnKindsList) {
if (factionPawnKinds.PawnKinds.Count > 0) {
- rowGroups.Add(new WidgetTable.RowGroup("" + factionPawnKinds.Faction.LabelCap.ToString() + "", factionPawnKinds.PawnKinds));
+ rowGroups.Add(new WidgetTable.RowGroup("" + factionPawnKinds.Faction.LabelCap.ToString() + "",
+ factionPawnKinds.PawnKinds.ConvertAll(f => new PawnKindOption(factionPawnKinds.Faction, f))));
}
}
if (!PrepareCarefully.Instance.Providers.PawnKinds.PawnKindsWithNoFaction.EnumerableNullOrEmpty()) {
- rowGroups.Add(new WidgetTable.RowGroup("Other", PrepareCarefully.Instance.Providers.PawnKinds.PawnKindsWithNoFaction));
+ rowGroups.Add(new WidgetTable.RowGroup("Other", PrepareCarefully.Instance.Providers.PawnKinds.PawnKindsWithNoFaction.Select(k => new PawnKindOption(null, k))));
}
DialogPawnKinds dialog = new DialogPawnKinds() {
HeaderLabel = "EdB.PC.Panel.PawnList.SelectFaction".Translate(),
- SelectAction = (PawnKindDef pawnKind) => { selected = pawnKind; },
+ SelectAction = (PawnKindOption option) => { selected = option; },
RowGroups = rowGroups,
DisabledOptions = disabled,
CloseAction = () => {
@@ -434,7 +443,8 @@ protected void ShowPawnKindDialog() {
Selected = selected,
ShowRace = PrepareCarefully.Instance.Providers.PawnKinds.AnyNonHumanPawnKinds && !PawnKindRaceDiversificationEnabled
};
- dialog.ScrollTo(PrepareCarefully.Instance.State.LastSelectedPawnKindDef);
+ dialog.ScrollToWhenOpened(PrepareCarefully.Instance.State.LastSelectedPawnKindDef);
+ //Logger.Debug("ScrollToWhenOpened = " + PrepareCarefully.Instance.State.LastSelectedPawnKindDef);
Find.WindowStack.Add(dialog);
}
diff --git a/Source/PanelRandomize.cs b/Source/PanelRandomize.cs
index ca5d390..c19388e 100644
--- a/Source/PanelRandomize.cs
+++ b/Source/PanelRandomize.cs
@@ -1,5 +1,9 @@
using RimWorld;
using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
using UnityEngine;
using Verse;
using Verse.Sound;
@@ -10,8 +14,17 @@ public class PanelRandomize : PanelBase {
public event RandomizeAllHandler RandomizeAllClicked;
public override void Draw(State state) {
- base.Draw(state);
+ if (ModsConfig.BiotechActive) {
+ DrawForBiotech(state);
+ return;
+ }
+ else {
+ DrawForNonBiotech(state);
+ }
+ }
+ public void DrawForNonBiotech(State state) {
+ base.Draw(state);
Rect randomRect = new Rect(
PanelRect.x + PanelRect.width / 2 - Textures.TextureButtonRandomLarge.width / 2 - 1,
PanelRect.y + PanelRect.height / 2 - Textures.TextureButtonRandomLarge.height / 2,
@@ -31,7 +44,163 @@ public override void Draw(State state) {
}
GUI.color = Color.white;
+ }
+
+ public void DrawForBiotech(State state) {
+ base.Draw(state);
+
+ var texture = DevelopmentalStageIconTexture(state.CurrentPawn.RandomizeDevelopmentalStage);
+ float buttonSize = 20f;
+ Rect dropdownRect = new Rect(PanelRect.x + 6, PanelRect.y + PanelRect.height * 0.25f - buttonSize * 0.5f, 34.0f, 18.0f);
+ if (WidgetDropdown.ImageButton(dropdownRect,texture, new Vector2(buttonSize, buttonSize), false, false, true)) {
+ List options = new List {
+ new FloatMenuOption("Adult".Translate().CapitalizeFirst(), delegate
+ {
+ state.CurrentPawn.RandomizeDevelopmentalStage = DevelopmentalStage.Adult;
+ }, Textures.TextureAdult, Color.white),
+ new FloatMenuOption("Child".Translate().CapitalizeFirst(), delegate
+ {
+ state.CurrentPawn.RandomizeDevelopmentalStage = DevelopmentalStage.Child;
+ }, Textures.TextureChild, Color.white),
+ new FloatMenuOption("Baby".Translate().CapitalizeFirst(), delegate
+ {
+ state.CurrentPawn.RandomizeDevelopmentalStage = DevelopmentalStage.Baby;
+ }, Textures.TextureBaby, Color.white)
+ };
+ Find.WindowStack.Add(new FloatMenu(options));
+ }
+ string tipTitle = "";
+ if (state.CurrentPawn.Pawn.DevelopmentalStage == DevelopmentalStage.Adult) {
+ tipTitle = "Adult".Translate().CapitalizeFirst();
+ }
+ else if (state.CurrentPawn.Pawn.DevelopmentalStage == DevelopmentalStage.Child) {
+ tipTitle = "Child".Translate().CapitalizeFirst();
+ }
+ else {
+ tipTitle = "Baby".Translate().CapitalizeFirst();
+ }
+ tipTitle = tipTitle.Colorize(ColoredText.TipSectionTitleColor);
+ TooltipHandler.TipRegion(dropdownRect, "EdB.PC.Panel.Randomize.Tip.DevelopmentalStage".Translate(tipTitle));
+
+ if (state.CurrentPawn.RandomizeXenotype != null) {
+ texture = state.CurrentPawn.RandomizeXenotype.Icon;
+ }
+ else if (state.CurrentPawn.RandomizeCustomXenotype != null) {
+ texture = state.CurrentPawn.RandomizeCustomXenotype.IconDef.Icon;
+ }
+ else if (state.CurrentPawn.RandomizeAnyNonArchite) {
+ texture = Textures.TextureButtonRandom;
+ }
+ else {
+ texture = null;
+ }
+ buttonSize = 22.0f;
+ dropdownRect = new Rect(PanelRect.x + 6, PanelRect.y + PanelRect.height * 0.75f - buttonSize * 0.5f, 32.0f, 18.0f);
+ if (WidgetDropdown.ImageButton(dropdownRect, texture, new Vector2(buttonSize, buttonSize), false, false, true)) {
+ List list = new List {
+ new FloatMenuOption("AnyNonArchite".Translate().CapitalizeFirst(), delegate
+ {
+ state.CurrentPawn.RandomizeXenotype = null;
+ state.CurrentPawn.RandomizeCustomXenotype = null;
+ state.CurrentPawn.RandomizeAnyNonArchite = true;
+ }),
+ new FloatMenuOption("XenotypeEditor".Translate() + "...", delegate
+ {
+ Find.WindowStack.Add(new Dialog_CreateXenotype(-1, delegate
+ {
+ CharacterCardUtility.cachedCustomXenotypes = null;
+ }));
+ })
+ };
+ foreach (XenotypeDef item in DefDatabase.AllDefs.OrderBy((XenotypeDef x) => 0f - x.displayPriority)) {
+ XenotypeDef xenotype = item;
+ list.Add(new FloatMenuOption(xenotype.LabelCap, delegate
+ {
+ state.CurrentPawn.RandomizeXenotype = xenotype;
+ state.CurrentPawn.RandomizeCustomXenotype = null;
+ state.CurrentPawn.RandomizeAnyNonArchite = false;
+ },
+ xenotype.Icon, XenotypeDef.IconColor, MenuOptionPriority.Default, delegate (Rect r)
+ {
+ TooltipHandler.TipRegion(r, xenotype.descriptionShort ?? xenotype.description);
+ },
+ null, 24f, (Rect r) => Widgets.InfoCardButton(r.x, r.y + 3f, xenotype) ? true : false, null, playSelectionSound: true, 0, HorizontalJustification.Left, extraPartRightJustified: true));
+ }
+ var customXenotypes = ReflectionUtil.GetStaticPropertyValue>(typeof(CharacterCardUtility), "CustomXenotypes");
+ if (customXenotypes != null) {
+ foreach (CustomXenotype customXenotype in customXenotypes) {
+ CustomXenotype customInner = customXenotype;
+ list.Add(new FloatMenuOption(customInner.name.CapitalizeFirst() + " (" + "Custom".Translate() + ")", delegate
+ {
+ Logger.Debug("Customized Xenotype, XenotypeDef: " + state.CurrentPawn.Pawn.genes.Xenotype?.defName);
+ Logger.Debug("Customized Xenotype: " + state.CurrentPawn.Pawn.genes.CustomXenotype?.name);
+ state.CurrentPawn.RandomizeCustomXenotype = customInner;
+ state.CurrentPawn.RandomizeXenotype = null;
+ state.CurrentPawn.RandomizeAnyNonArchite = false;
+ },
+ customInner.IconDef.Icon, XenotypeDef.IconColor, MenuOptionPriority.Default, null, null, 24f, delegate (Rect r) {
+ if (Widgets.ButtonImage(new Rect(r.x, r.y + (r.height - r.width) / 2f, r.width, r.width), TexButton.DeleteX, GUI.color)) {
+ Find.WindowStack.Add(Dialog_MessageBox.CreateConfirmation("ConfirmDelete".Translate(customInner.name.CapitalizeFirst()), delegate {
+ string path = GenFilePaths.AbsFilePathForXenotype(customInner.name);
+ if (File.Exists(path)) {
+ File.Delete(path);
+ CharacterCardUtility.cachedCustomXenotypes = null;
+ }
+ }, destructive: true));
+ return true;
+ }
+ return false;
+ }, null, playSelectionSound: true, 0, HorizontalJustification.Left, extraPartRightJustified: true));
+ }
+ }
+ Find.WindowStack.Add(new FloatMenu(list));
+ }
+ string xenotypeTipLabel = "";
+ if (state.CurrentPawn.RandomizeXenotype != null) {
+ xenotypeTipLabel = state.CurrentPawn.RandomizeXenotype.LabelCap;
+ }
+ else if (state.CurrentPawn.RandomizeCustomXenotype != null) {
+ xenotypeTipLabel = state.CurrentPawn.RandomizeCustomXenotype.name;
+ }
+ else if (state.CurrentPawn.RandomizeAnyNonArchite) {
+ xenotypeTipLabel = "AnyNonArchite".Translate().CapitalizeFirst();
+ }
+ xenotypeTipLabel = xenotypeTipLabel.Colorize(ColoredText.TipSectionTitleColor);
+ TooltipHandler.TipRegion(dropdownRect, "EdB.PC.Panel.Randomize.Tip.Xenotype".Translate(xenotypeTipLabel));
+
+ Rect randomRect = new Rect(
+ PanelRect.x + PanelRect.width - Textures.TextureButtonRandomLarge.width - 16,
+ PanelRect.y + PanelRect.HalfHeight() - Textures.TextureButtonRandomLarge.height * 0.5f,
+ Textures.TextureButtonRandomLarge.width,
+ Textures.TextureButtonRandomLarge.height
+ );
+ if (randomRect.Contains(Event.current.mousePosition)) {
+ GUI.color = Style.ColorButtonHighlight;
+ }
+ else {
+ GUI.color = Style.ColorButton;
+ }
+ GUI.DrawTexture(randomRect, Textures.TextureButtonRandomLarge);
+ if (Widgets.ButtonInvisible(randomRect, false)) {
+ SoundDefOf.Tick_Low.PlayOneShotOnCamera();
+ RandomizeAllClicked();
+ }
+ GUI.color = Color.white;
+ GUI.color = Style.ColorTabViewBackground;
+ Widgets.DrawLineVertical(PanelRect.x + 48, PanelRect.y + 6, PanelRect.height - 12);
+ GUI.color = Color.white;
+ }
+ protected Texture2D DevelopmentalStageIconTexture(DevelopmentalStage developmentalStage) {
+ if (developmentalStage == DevelopmentalStage.Baby) {
+ return Textures.TextureBaby;
+ }
+ else if (developmentalStage == DevelopmentalStage.Child) {
+ return Textures.TextureChild;
+ }
+ else {
+ return Textures.TextureAdult;
+ }
}
}
}
diff --git a/Source/PanelRelationshipsParentChild.cs b/Source/PanelRelationshipsParentChild.cs
index 91aa209..51a81ee 100644
--- a/Source/PanelRelationshipsParentChild.cs
+++ b/Source/PanelRelationshipsParentChild.cs
@@ -43,12 +43,12 @@ public class PanelRelationshipsParentChild : PanelBase {
private Color ColorChild = new Color(22f / 255f, 22f / 255f, 23f / 255f);
private Color ColorChildEmpty = new Color(22f / 255f, 22f / 255f, 23f / 255f, 0.40f);
- private HashSet visibleBackstories = new HashSet();
+ private HashSet visibleBackstories = new HashSet();
public PanelRelationshipsParentChild() {
// TODO: Pull this out and put it in a utility somewhere, i.e. ProviderBackstory.
- foreach (Backstory backstory in BackstoryDatabase.allBackstories.Values) {
- if (backstory.identifier.StartsWith("FactionLeader")) {
+ foreach (BackstoryDef backstory in DefDatabase.AllDefs) {
+ if (backstory.identifier != null && backstory.identifier.StartsWith("FactionLeader")) {
visibleBackstories.Add(backstory);
}
}
diff --git a/Source/PanelSkills.cs b/Source/PanelSkills.cs
index be40b36..0cd64f4 100644
--- a/Source/PanelSkills.cs
+++ b/Source/PanelSkills.cs
@@ -122,7 +122,7 @@ protected override void DrawPanelContent(State state) {
Text.Font = GameFont.Small;
foreach (var skill in customPawn.Pawn.skills.skills) {
SkillDef def = skill.def;
- bool disabled = skill.TotallyDisabled;
+ bool disabled = IsSkillDisabled(customPawn, skill);
// Draw the label.
GUI.color = Style.ColorText;
@@ -222,9 +222,20 @@ public static void FillableBar(Rect rect, float fillPercent, Texture2D fillTex)
GUI.DrawTexture(rect, fillTex);
}
+ public static bool IsSkillDisabled(CustomPawn customPawn, SkillRecord skill) {
+ if (skill.TotallyDisabled) {
+ return true;
+ }
+ // TODO: Do we need to look at life stages to figure this out?
+ if (customPawn.Pawn.DevelopmentalStage == DevelopmentalStage.Newborn || customPawn.Pawn.DevelopmentalStage == DevelopmentalStage.Baby) {
+ return true;
+ }
+ return false;
+ }
+
private void DrawSkill(CustomPawn customPawn, SkillRecord skill, Rect rect) {
int level = skill.Level;
- bool disabled = skill.TotallyDisabled;
+ bool disabled = IsSkillDisabled(customPawn, skill);
if (!disabled) {
float barSize = (level > 0 ? (float)level : 0) / 20f;
FillableBar(rect, barSize, Textures.TextureSkillBarFill);
diff --git a/Source/PanelTraits.cs b/Source/PanelTraits.cs
index d0605b8..d10ae34 100644
--- a/Source/PanelTraits.cs
+++ b/Source/PanelTraits.cs
@@ -67,10 +67,18 @@ public override float Draw(State state, float y) {
if (trait != null) {
field.Label = trait.LabelCap;
field.Tip = GetTraitTip(trait, currentPawn);
+ field.Color = Style.ColorText;
+ if (trait.Suppressed) {
+ field.Color = ColoredText.SubtleGrayColor;
+ }
+ else if (trait.sourceGene != null) {
+ field.Color = ColoredText.GeneColor;
+ }
}
else {
field.Label = null;
field.Tip = null;
+ field.Color = Style.ColorText;
}
Trait localTrait = trait;
int localIndex = index;
@@ -147,7 +155,11 @@ public override float Draw(State state, float y) {
// If the index is still zero, then the pawn has no traits. Draw the "none" label.
if (index == 0) {
GUI.color = Style.ColorText;
- Widgets.Label(FieldRect.InsetBy(6, 0).OffsetBy(0, y - 4), "EdB.PC.Panel.Traits.None".Translate());
+ string message = "EdB.PC.Panel.Traits.None".Translate();
+ if (state.CurrentPawn.Pawn.DevelopmentalStage.Baby()) {
+ message = "TraitsDevelopLaterBaby".Translate();
+ }
+ Widgets.Label(FieldRect.InsetBy(6, 0).OffsetBy(0, y - 4), message);
y += FieldRect.height - 4;
}
@@ -159,59 +171,62 @@ public override float Draw(State state, float y) {
clickAction = null;
}
- // Randomize traits button.
- Rect randomizeRect = new Rect(Width - 32, top + 9, 22, 22);
- if (randomizeRect.Contains(Event.current.mousePosition)) {
- GUI.color = Style.ColorButtonHighlight;
- }
- else {
- GUI.color = Style.ColorButton;
- }
- GUI.DrawTexture(randomizeRect, Textures.TextureButtonRandom);
- if (Widgets.ButtonInvisible(randomizeRect, false)) {
- SoundDefOf.Tick_Low.PlayOneShotOnCamera();
- tipCache.Invalidate();
- TraitsRandomized();
- }
+ // Don't show add or randomize buttons if the pawn is a baby
+ if (!state.CurrentPawn.Pawn.DevelopmentalStage.Baby()) {
+ // Randomize traits button.
+ Rect randomizeRect = new Rect(Width - 32, top + 9, 22, 22);
+ if (randomizeRect.Contains(Event.current.mousePosition)) {
+ GUI.color = Style.ColorButtonHighlight;
+ }
+ else {
+ GUI.color = Style.ColorButton;
+ }
+ GUI.DrawTexture(randomizeRect, Textures.TextureButtonRandom);
+ if (Widgets.ButtonInvisible(randomizeRect, false)) {
+ SoundDefOf.Tick_Low.PlayOneShotOnCamera();
+ tipCache.Invalidate();
+ TraitsRandomized();
+ }
- // Add trait button.
- Rect addRect = new Rect(randomizeRect.x - 24, top + 12, 16, 16);
- Style.SetGUIColorForButton(addRect);
- int traitCount = state.CurrentPawn.Traits.Count();
- bool addButtonEnabled = (state.CurrentPawn != null && traitCount < Constraints.MaxTraits);
- if (!addButtonEnabled) {
- GUI.color = Style.ColorButtonDisabled;
- }
- GUI.DrawTexture(addRect, Textures.TextureButtonAdd);
- if (addButtonEnabled && Widgets.ButtonInvisible(addRect, false)) {
- ComputeDisallowedTraits(currentPawn, null);
- SoundDefOf.Tick_Low.PlayOneShotOnCamera();
- Trait selectedTrait = null;
- Dialog_Options dialog = new Dialog_Options(providerTraits.Traits) {
- ConfirmButtonLabel = "EdB.PC.Common.Add".Translate(),
- NameFunc = (Trait t) => {
- return t.LabelCap;
- },
- DescriptionFunc = (Trait t) => {
- return GetTraitTip(t, state.CurrentPawn);
- },
- SelectedFunc = (Trait t) => {
- return selectedTrait == t;
- },
- SelectAction = (Trait t) => {
- selectedTrait = t;
- },
- EnabledFunc = (Trait t) => {
- return !disallowedTraitDefs.Contains(t.def);
- },
- CloseAction = () => {
- if (selectedTrait != null) {
- TraitAdded(selectedTrait);
- tipCache.Invalidate();
+ // Add trait button.
+ Rect addRect = new Rect(randomizeRect.x - 24, top + 12, 16, 16);
+ Style.SetGUIColorForButton(addRect);
+ int traitCount = state.CurrentPawn.Traits.Count();
+ bool addButtonEnabled = (state.CurrentPawn != null && traitCount < Constraints.MaxTraits);
+ if (!addButtonEnabled) {
+ GUI.color = Style.ColorButtonDisabled;
+ }
+ GUI.DrawTexture(addRect, Textures.TextureButtonAdd);
+ if (addButtonEnabled && Widgets.ButtonInvisible(addRect, false)) {
+ ComputeDisallowedTraits(currentPawn, null);
+ SoundDefOf.Tick_Low.PlayOneShotOnCamera();
+ Trait selectedTrait = null;
+ Dialog_Options dialog = new Dialog_Options(providerTraits.Traits) {
+ ConfirmButtonLabel = "EdB.PC.Common.Add".Translate(),
+ NameFunc = (Trait t) => {
+ return t.LabelCap;
+ },
+ DescriptionFunc = (Trait t) => {
+ return GetTraitTip(t, state.CurrentPawn);
+ },
+ SelectedFunc = (Trait t) => {
+ return selectedTrait == t;
+ },
+ SelectAction = (Trait t) => {
+ selectedTrait = t;
+ },
+ EnabledFunc = (Trait t) => {
+ return !disallowedTraitDefs.Contains(t.def);
+ },
+ CloseAction = () => {
+ if (selectedTrait != null) {
+ TraitAdded(selectedTrait);
+ tipCache.Invalidate();
+ }
}
- }
- };
- Find.WindowStack.Add(dialog);
+ };
+ Find.WindowStack.Add(dialog);
+ }
}
// Remove any traits that were marked for deletion
diff --git a/Source/PanelXenotype.cs b/Source/PanelXenotype.cs
new file mode 100644
index 0000000..732e587
--- /dev/null
+++ b/Source/PanelXenotype.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using RimWorld;
+using Verse;
+using Verse.Sound;
+
+namespace EdB.PrepareCarefully {
+ public class PanelXenotype : PanelModule {
+ public static readonly Vector2 FieldPadding = new Vector2(6, 6);
+
+ public Rect FieldRect;
+ protected Field FieldXenotype = new Field();
+ protected LabelTrimmer labelTrimmer = new LabelTrimmer();
+
+ public override void Resize(float width) {
+ base.Resize(width);
+ FieldRect = new Rect(FieldPadding.x, 0, width - FieldPadding.x * 2, 30);
+ }
+
+ public float Measure() {
+ return 0;
+ }
+
+ public override bool IsVisible(State state) {
+ return ModsConfig.BiotechActive;
+ }
+
+ public override float Draw(State state, float y) {
+ float top = y;
+ y += Margin.y;
+
+ y += DrawHeader(y, Width, "Xenotype".Translate().CapitalizeFirst().Resolve());
+
+ CustomPawn pawn = state.CurrentPawn;
+ Pawn_GeneTracker geneTracker = pawn.Pawn.genes;
+ XenotypeDef xenotypeDef = geneTracker?.Xenotype;
+ CustomXenotype customXenotype = geneTracker?.CustomXenotype;
+
+ FieldXenotype.Rect = FieldRect.OffsetBy(0, y);
+ labelTrimmer.Rect = FieldXenotype.Rect.InsetBy(8, 0);
+
+ if (customXenotype != null) {
+ FieldXenotype.Label = labelTrimmer.TrimLabelIfNeeded(customXenotype.name);
+ }
+ else if (xenotypeDef != null) {
+ FieldXenotype.Label = labelTrimmer.TrimLabelIfNeeded(xenotypeDef.LabelCap);
+ }
+ FieldXenotype.Enabled = true;
+ FieldXenotype.ClickAction = () => {
+ Find.WindowStack.Add(new Dialog_ViewGenes(pawn.Pawn));
+ };
+ FieldXenotype.DrawIconFunc = (Rect rect) => {
+ if (xenotypeDef != null) {
+ GUI.DrawTexture(rect, xenotypeDef.Icon);
+ }
+ else if (customXenotype != null) {
+ GUI.DrawTexture(rect, customXenotype.IconDef?.Icon);
+ }
+ };
+ FieldXenotype.IconSizeFunc = () => new Vector2(24, 24);
+
+ FieldXenotype.Draw();
+
+ y += FieldRect.height;
+
+ Text.Font = GameFont.Small;
+ GUI.color = Color.white;
+ Text.Anchor = TextAnchor.UpperLeft;
+
+ y += Margin.y;
+
+ return y - top;
+ }
+
+ }
+}
diff --git a/Source/PawnColorUtils.cs b/Source/PawnColorUtils.cs
deleted file mode 100644
index e58dfac..0000000
--- a/Source/PawnColorUtils.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using RimWorld;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using UnityEngine;
-using Verse;
-
-namespace EdB.PrepareCarefully {
- public class PawnColorUtils {
- // The values will match the color values in the PawnSkinColors class. We use a round-about way of getting at
- // those color values in the InitializeColors() method.
- public static Color[] Colors;
-
- // The same colors, but rounded to 3 fractional digits. When colors are saved to a preset, they are
- // automatically rounded, so we need to use these rounded values when loading them. We could avoid this if
- // we didn't store the color directly in the preset, and instead used the same value that the game stores in
- // save files. Since we didn't do this from the beginning, we'll keeping using colors for now to keep presets
- // backwards-compatibile.
- public static Color[] RoundedColors;
-
- // The values will match the color values in the PawnSkinColors class.
- public static float[] ColorValues;
-
- // Populates color arrays from PawnSkinColors.SkinColors. Uses an indirect method of getting the color values
- // instead of just copying the color list via reflection. This will make it work better with mods that
- // detour the color methods in that class--as long as they detour the GetSkinDataIndexOfMelanin() method.
- public static void InitializeColors() {
- List values = new List();
-
- // Iterate all values from 0.0f to 1.0f, using increments of 0.01f, to get the left index for each value.
- // Use this technique to construct a list of all of the indexes and their values. Once we have the list
- // of indexes and their values, we can use the GetSkinColor() method to get the actual colors.
- int currentIndex = 0;
- values.Add(0.0f);
- float f = 0.01f;
- int counter = 1;
- while (f < 1.0f) {
- int result = Reflection.PawnSkinColors.GetSkinDataIndexOfMelanin(f);
- if (result != currentIndex) {
- currentIndex = result;
- values.Add(f);
- }
- counter++;
- double d = (double)counter / 100.0;
- f = (float)d;
- }
- values.Add(1.0f);
-
- // Allocate the arrays and fill them with the correct values.
- int length = values.Count;
- Colors = new Color[length];
- ColorValues = new float[length];
- RoundedColors = new Color[length];
- for (int i = 0; i < length; i++) {
- float v = values[i];
- Color color = PawnSkinColors.GetSkinColor(v);
- Colors[i] = color;
- RoundedColors[i] = color;
- RoundedColors[i].r = (float)Math.Round(color.r, 3);
- RoundedColors[i].g = (float)Math.Round(color.g, 3);
- RoundedColors[i].b = (float)Math.Round(color.b, 3);
- RoundedColors[i].a = (float)Math.Round(color.a, 3);
- ColorValues[i] = v;
- //Logger.Debug("Color added: (" + color.r + ", " + color.g + ", " + color.b + ")");
- }
- }
-
- public static float GetRelativeLerpValue(float value) {
- int leftIndex = GetLeftIndexForValue(value);
- if (leftIndex == Colors.Length - 1) {
- return 0.0f;
- }
-
- int rightIndex = leftIndex + 1;
- float t = Mathf.InverseLerp(ColorValues[leftIndex], ColorValues[rightIndex], value);
- return t;
- }
-
- public static float GetValueFromRelativeLerp(int leftIndex, float lerp) {
- if (leftIndex >= Colors.Length - 1) {
- return 1.0f;
- }
- else if (leftIndex < 0) {
- return 0.0f;
- }
-
- int rightIndex = leftIndex + 1;
- float result = Mathf.Lerp(ColorValues[leftIndex], ColorValues[rightIndex], lerp);
-
- return result;
- }
-
- public static int GetLeftIndexForValue(float value) {
- int result = 0;
- for (int i = 0; i < Colors.Length; i++) {
- if (value < ColorValues[i]) {
- break;
- }
- result = i;
- }
- return result;
- }
-
- private static bool Between(Color color, Color a, Color b) {
- if (color.r >= a.r && color.r <= b.r || color.r <= a.r && color.r >= b.r) {
- if (color.g >= a.g && color.g <= b.g || color.g <= a.g && color.g >= b.g) {
- if (color.b >= a.b && color.b <= b.b || color.b <= a.b && color.b >= b.b) {
- return true;
- }
- }
- }
- return false;
- }
-
- public static float FindMelaninValueFromColor(Color color) {
- int colorCount = Colors.Length;
- for (int i = 0; i < colorCount - 1; i++) {
- Color a = RoundedColors[i];
- Color b = RoundedColors[i + 1];
- bool between = Between(color, a, b);
- if (!between) {
- continue;
- }
- Color c = a;
- Color d = b;
- bool ignorer = false;
- bool ignoreg = false;
- bool ignoreb = false;
- if (c.r == d.r) {
- ignorer = true;
- }
- if (c.g == d.g) {
- ignoreg = true;
- }
- if (c.b == d.b) {
- ignoreb = true;
- }
- float tr = (color.r - c.r) / (d.r - c.r);
- float tg = (color.g - c.g) / (d.g - c.g);
- float tb = (color.b - c.b) / (d.b - c.b);
- bool invalid = false;
- float count = 0.0f;
- float total = 0.0f;
- if (!ignorer) {
- if (tr < 0.0f && tr > 1.0f) {
- invalid = true;
- }
- else {
- count += 1.0f;
- total += tr;
- }
- }
- if (!ignoreg) {
- if (tg < 0.0f && tg > 1.0f) {
- invalid = true;
- }
- else {
- count += 1.0f;
- total += tg;
- }
- }
- if (!ignoreb) {
- if (tb < 0.0f && tb > 1.0f) {
- invalid = true;
- }
- else {
- count += 1.0f;
- total += tb;
- }
- }
- if (invalid) {
- continue;
- }
- float t = count > 0 ? total / count : 0;
- float result = GetValueFromRelativeLerp(i, t);
-
- return result;
- }
- Logger.Warning("Could not find a valid matching value for the saved Color");
- return 0.5f;
- }
- }
-}
-
diff --git a/Source/PawnCompRules.cs b/Source/PawnCompRules.cs
index 3e0873a..9cc8f93 100644
--- a/Source/PawnCompRules.cs
+++ b/Source/PawnCompRules.cs
@@ -181,17 +181,17 @@ public static void RemoveDefaultFacialStuff(Pawn pawn, Dictionary compLookup, HashSet savedComps) {
// If the pawn was saved when vanilla hair expanded was not enabled, but it was enabled when they load the pawn,
// then they may end up with a beard by default. This post-load action clears out that default beard.
- if (!savedComps.Contains("AlienRace.AlienPartGenerator+AlienComp")) {
- if (compLookup.TryGetValue("AlienRace.AlienPartGenerator+AlienComp", out ThingComp c)) {
- string crownType = ReflectionUtil.GetFieldValue(c, "crownType");
- if (crownType != null) {
- CustomHeadType headType = pawn.HeadType;
- if (headType != null && headType.AlienCrownType != crownType) {
- ReflectionUtil.SetFieldValue(c, "crownType", null);
- }
- }
- }
- }
+ //if (!savedComps.Contains("AlienRace.AlienPartGenerator+AlienComp")) {
+ // if (compLookup.TryGetValue("AlienRace.AlienPartGenerator+AlienComp", out ThingComp c)) {
+ // string crownType = ReflectionUtil.GetFieldValue(c, "crownType");
+ // if (crownType != null) {
+ // CustomHeadType headType = pawn.HeadType;
+ // if (headType != null && headType.AlienCrownType != crownType) {
+ // ReflectionUtil.SetFieldValue(c, "crownType", null);
+ // }
+ // }
+ // }
+ //}
}
}
diff --git a/Source/PawnGenerationRequestWrapper.cs b/Source/PawnGenerationRequestWrapper.cs
index c062966..6c34864 100644
--- a/Source/PawnGenerationRequestWrapper.cs
+++ b/Source/PawnGenerationRequestWrapper.cs
@@ -9,157 +9,122 @@
using Verse.Sound;
namespace EdB.PrepareCarefully {
- class PawnGenerationRequestWrapper {
- private PawnKindDef kindDef = Faction.OfPlayer.def.basicMemberKind;
- private Faction faction = Faction.OfPlayer;
- private PawnGenerationContext context = PawnGenerationContext.PlayerStarter;
- private float? fixedBiologicalAge = null;
- private float? fixedChronologicalAge = null;
- private Gender? fixedGender = null;
- private bool worldPawnFactionDoesntMatter = false;
- private bool mustBeCapableOfViolence = false;
- private Ideo fixedIdeology = null;
+ public class PawnGenerationRequestWrapper {
+ public PawnKindDef KindDef { get; set; } = Faction.OfPlayer.def.basicMemberKind;
+ public Faction Faction { get; set; } = Faction.OfPlayer;
+ public PawnGenerationContext Context { get; set; } = PawnGenerationContext.PlayerStarter;
+ public float? FixedBiologicalAge { get; set; } = null;
+ public float? FixedChronologicalAge { get; set; } = null;
+ public Gender? FixedGender { get; set; } = null;
+ public bool WorldPawnFactionDoesntMatter { get; set; } = false;
+ public bool MustBeCapableOfViolence { get; set; } = false;
+ public Ideo FixedIdeology { get; set; } = null;
+ public XenotypeDef ForcedXenotype { get; set; } = null;
+ public CustomXenotype ForcedCustomXenotype { get; set; } = null;
+ public List AllowedXenotypes { get; set; } = null;
+ public float ForceBaselinerChance { get; set; } = 0f;
+ public IEnumerable ForcedTraits { get; set; } = Enumerable.Empty();
+ public DevelopmentalStage DevelopmentalStage { get; set; } = DevelopmentalStage.Adult;
+ public List ForcedXenogenes { get; set; } = null;
+ public List ForcedEndogenes { get; set; } = null;
+ public string FixedLastName { get; set; } = null;
+ public string FixedBirthName { get; set; } = null;
+ public RoyalTitleDef FixedTitle { get; set; } = null;
+ public bool AllowDowned { get; set; } = false;
public PawnGenerationRequestWrapper() {
}
private PawnGenerationRequest CreateRequest() {
- //public PawnGenerationRequest (
-
- //string fixedBirthName = null,
- //RoyalTitleDef fixedTitle = null)
-
- /*
- * PawnKindDef kind
- * Faction faction = null
- * PawnGenerationContext context = PawnGenerationContext.NonPlayer
- * int tile = -1
- * bool forceGenerateNewPawn = false
- * bool newborn = false
- * bool allowDead = false
- * bool allowDowned = false
- * bool canGeneratePawnRelations = true
- * bool mustBeCapableOfViolence = false
- * float colonistRelationChanceFactor = 1
- * bool forceAddFreeWarmLayerIfNeeded = false
- * bool allowGay = true
- * bool allowFood = true
- * bool allowAddictions = true
- * bool inhabitant = false
- * bool certainlyBeenInCryptosleep = false
- * bool forceRedressWorldPawnIfFormerColonist = false
- * bool worldPawnFactionDoesntMatter = false
- * float biocodeWeaponChance = 0
- * float biocodeApparelChance = 0
- * Pawn extraPawnForExtraRelationChance = null
- * float relationWithExtraPawnChanceFactor = 1
- * Predicate validatorPreGear = null
- * Predicate validatorPostGear = null
- * IEnumerable forcedTraits = null
- * IEnumerable prohibitedTraits = null
- * float? minChanceToRedressWorldPawn = null
- * float? fixedBiologicalAge = null
- * float? fixedChronologicalAge = null
- * Gender? fixedGender = null
- * float? fixedMelanin = null
- * string fixedLastName = null
- * string fixedBirthName = null
- * RoyalTitleDef fixedTitle = null
- * Ideo fixedIdeo = null
- * bool forceNoIdeo = false
- * bool forceNoBackstory = false);
- */
-
+ // TODO: Should dynamically look at all of the life stages in the developmental stage to see if they have any "always downed" life stages like the "baby" life stage.
+ bool allowDowned = AllowDowned;
+ if (DevelopmentalStage == DevelopmentalStage.Baby) {
+ allowDowned = true;
+ }
+ var dedupedForcedXenogenes = RemoveDuplicateXenogenes(ForcedXenogenes);
return new PawnGenerationRequest(
- kindDef, // PawnKindDef kind
- faction, // Faction faction = null
- context, // PawnGenerationContext context = PawnGenerationContext.NonPlayer
+ KindDef, //PawnKindDef kind,
+ Faction, //Faction faction = null,
+ Context, //PawnGenerationContext context = PawnGenerationContext.NonPlayer,
-1, //int tile = -1,
true, //bool forceGenerateNewPawn = false,
- false, //bool newborn = false,
false, //bool allowDead = false,
- false, //bool allowDowned = false,
+ allowDowned, //bool allowDowned = false,
false, //bool canGeneratePawnRelations = true,
- mustBeCapableOfViolence, //bool mustBeCapableOfViolence = false,
+ MustBeCapableOfViolence, //bool mustBeCapableOfViolence = false,
0f, //float colonistRelationChanceFactor = 1f,
false, //bool forceAddFreeWarmLayerIfNeeded = false,
true, //bool allowGay = true,
+ false, //bool allowPregnant = false,
false, //bool allowFood = true,
- false, //bool allowAddictions = true,
- false, // bool inhabitant = false
- false, // bool certainlyBeenInCryptosleep = false
- false, // bool forceRedressWorldPawnIfFormerColonist = false
- worldPawnFactionDoesntMatter, // bool worldPawnFactionDoesntMatter = false
- 0f, //float biocodeWeaponChance = 0f,
+ false, //bool allowAddictions = true,
+ false, //bool inhabitant = false,
+ false, //bool certainlyBeenInCryptosleep = false,
+ false, //bool forceRedressWorldPawnIfFormerColonist = false,
+ WorldPawnFactionDoesntMatter, //bool worldPawnFactionDoesntMatter = false,
+ 0f, //float biocodeWeaponChance = 0f,
0f, //float biocodeApparelChance = 0f,
- null, //Pawn extraPawnForExtraRelationChance = null,
- 1f, //float relationWithExtraPawnChanceFactor = 1f,
- null, // Predicate < Pawn > validatorPreGear = null
- null, // Predicate < Pawn > validatorPostGear = null
- Enumerable.Empty(), //IEnumerable forcedTraits = null,
- Enumerable.Empty(), //IEnumerable prohibitedTraits = null,
- null, // float ? minChanceToRedressWorldPawn = null
- fixedBiologicalAge, // float ? fixedBiologicalAge = null
- fixedChronologicalAge, // float ? fixedChronologicalAge = null
- fixedGender, // Gender ? fixedGender = null
- null, // float ? fixedMelanin = null
- null, // string fixedLastName = null
- null, //string fixedBirthName = null,
- null, //RoyalTitleDef fixedTitle = null
- fixedIdeology, //Ideo fixedIdeo = null
- false, //bool forceNoIdeo = false
- false //bool forceNoBackstory = false
- ) {
- ForbidAnyTitle = true
- };
+ null, //Pawn extraPawnForExtraRelationChance = null,
+ 1f, //float relationWithExtraPawnChanceFactor = 1f,
+ null, //Predicate < Pawn > validatorPreGear = null,
+ null, //Predicate < Pawn > validatorPostGear = null,
+ ForcedTraits, //IEnumerable < TraitDef > forcedTraits = null,
+ Enumerable.Empty(), //IEnumerable < TraitDef > prohibitedTraits = null,
+ null, //float ? minChanceToRedressWorldPawn = null,
+ FixedBiologicalAge, //float ? fixedBiologicalAge = null,
+ FixedChronologicalAge, //float ? fixedChronologicalAge = null,
+ FixedGender, //Gender ? fixedGender = null,
+ FixedLastName, //string fixedLastName = null,
+ FixedBirthName, //string fixedBirthName = null,
+ FixedTitle, //RoyalTitleDef fixedTitle = null,
+ null, //Ideo fixedIdeo = null,
+ false, //bool forceNoIdeo = false,
+ false, //bool forceNoBackstory = false,
+ true, //bool forbidAnyTitle = false,
+ false, //bool forceDead = false,
+ dedupedForcedXenogenes, //List < GeneDef > forcedXenogenes = null,
+ ForcedEndogenes, //List < GeneDef > forcedEndogenes = null,
+ ForcedXenotype, //XenotypeDef forcedXenotype = null,
+ ForcedCustomXenotype, //CustomXenotype forcedCustomXenotype = null,
+ AllowedXenotypes, //List < XenotypeDef > allowedXenotypes = null,
+ ForceBaselinerChance, //float forceBaselinerChance = 0f,
+ DevelopmentalStage, //DevelopmentalStage developmentalStages = DevelopmentalStage.Adult,
+ null, //Func < XenotypeDef, PawnKindDef > pawnKindDefGetter = null,
+ null, //FloatRange ? excludeBiologicalAgeRange = null,
+ null, //FloatRange ? biologicalAgeRange = null,
+ false //bool forceRecruitable = false
+ );
}
public PawnGenerationRequest Request {
get {
return CreateRequest();
}
}
- public PawnKindDef KindDef {
- set {
- kindDef = value;
- }
- }
- public Faction Faction {
- set {
- faction = value;
- }
- }
- public PawnGenerationContext Context {
- set {
- context = value;
- }
- }
- public bool WorldPawnFactionDoesntMatter {
- set {
- worldPawnFactionDoesntMatter = value;
- }
- }
- public float? FixedBiologicalAge {
- set {
- fixedBiologicalAge = value;
- }
- }
- public float? FixedChronologicalAge {
- set {
- fixedChronologicalAge = value;
- }
- }
- public Gender? FixedGender {
- set {
- fixedGender = value;
+
+ // If the generation request specifies a forced xenotype and force xenogenes, the default pawn generator will not de-duplicate
+ // the genes and will instead add multiple copies. We de-dupe them here by removing duplicates from the forced xenogenes before
+ // we do the generation.
+ // Note that the default pawn generator does de-duplicate endogenes.
+ protected List RemoveDuplicateXenogenes(List forcedGenes) {
+ if (forcedGenes == null || forcedGenes.Count == 0 || (ForcedXenotype == null && ForcedCustomXenotype == null)) {
+ return forcedGenes;
}
- }
- public bool MustBeCapableOfViolence {
- set {
- mustBeCapableOfViolence = value;
+ HashSet geneSet = new HashSet(forcedGenes);
+ List genesToRemove = new List();
+ Logger.Debug(" Xenotype " + ForcedXenotype?.defName + " is inheritable = " + ForcedXenotype?.inheritable);
+ if (ForcedXenotype != null && !ForcedXenotype.inheritable) {
+ foreach (var g in ForcedXenotype.genes) {
+ if (geneSet.Contains(g)) {
+ genesToRemove.Add(g);
+ }
+ }
}
- }
- public Ideo FixedIdeology {
- set {
- fixedIdeology = value;
+ if (ForcedCustomXenotype != null && !ForcedCustomXenotype.inheritable) {
+ foreach (var g in ForcedCustomXenotype.genes) {
+ if (geneSet.Contains(g)) {
+ genesToRemove.Add(g);
+ }
+ }
}
+ return new List(forcedGenes.Where(g => !genesToRemove.Contains(g)));
}
}
}
diff --git a/Source/PawnLayerBody.cs b/Source/PawnLayerBody.cs
index 040642f..67dbdd9 100644
--- a/Source/PawnLayerBody.cs
+++ b/Source/PawnLayerBody.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Source/PawnLayerHead.cs b/Source/PawnLayerHead.cs
index 9d3b845..8eb89a7 100644
--- a/Source/PawnLayerHead.cs
+++ b/Source/PawnLayerHead.cs
@@ -23,7 +23,7 @@ public override List Options {
public override ColorSelectorType ColorSelectorType {
get {
- return ColorSelectorType.RGB;
+ return ColorSelectorType.Skin;
}
}
diff --git a/Source/PawnLayerOption.cs b/Source/PawnLayerOption.cs
index 8176a96..77cf3e5 100644
--- a/Source/PawnLayerOption.cs
+++ b/Source/PawnLayerOption.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -9,5 +9,6 @@ public abstract string Label {
get;
set;
}
+ public virtual bool Selectable { get; set; } = true;
}
}
diff --git a/Source/PawnLayerOptionBody.cs b/Source/PawnLayerOptionBody.cs
index 09ee766..ab3ead3 100644
--- a/Source/PawnLayerOptionBody.cs
+++ b/Source/PawnLayerOptionBody.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Source/PawnLayerOptionHead.cs b/Source/PawnLayerOptionHead.cs
index 3a7cb9c..ca7179d 100644
--- a/Source/PawnLayerOptionHead.cs
+++ b/Source/PawnLayerOptionHead.cs
@@ -1,4 +1,4 @@
-using RimWorld;
+using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -7,17 +7,25 @@
namespace EdB.PrepareCarefully {
public class PawnLayerOptionHead : PawnLayerOption {
+ private string label;
+ private HeadTypeDef headType;
public override string Label {
get {
- return HeadType.Label;
+ return label;
}
set {
throw new NotImplementedException();
}
}
- public CustomHeadType HeadType {
- get;
- set;
+ public HeadTypeDef HeadType {
+ get {
+ return headType;
+ }
+ set {
+ headType = value;
+ // TODO: Better if we were setting the names when creating the options in the provider
+ label = PrepareCarefully.Instance.Providers.HeadTypes.GetHeadTypeLabel(headType);
+ }
}
}
}
diff --git a/Source/PrepareCarefully.cs b/Source/PrepareCarefully.cs
index c218615..bf12be5 100644
--- a/Source/PrepareCarefully.cs
+++ b/Source/PrepareCarefully.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Reflection;
using Verse;
+using static RimWorld.ColonistBar;
namespace EdB.PrepareCarefully {
@@ -141,7 +142,6 @@ public void Initialize() {
Textures.Reset();
Clear();
InitializeProviders();
- PawnColorUtils.InitializeColors();
InitializePawns();
InitializeRelationshipManager(this.pawns);
InitializeDefaultEquipment();
@@ -186,8 +186,6 @@ protected void InitializeProviders() {
Providers.Titles = new ProviderTitles();
}
- // TODO:
- // Think about whether or not this is the best approach. Might need to do a bug report for the vanilla game?
// The tribal scenario adds a weapon with an invalid thing/stuff combination (jade knife). The
// knife ThingDef should allow the jade material, but it does not. We need this workaround to
// add the normally disallowed equipment to our equipment database.
@@ -290,6 +288,28 @@ record = AddNonStandardScenarioEquipmentEntry(key);
}
}
+ // Go through starting possessions
+ foreach (var pair in Verse.Find.GameInitData.startingPossessions) {
+ foreach (var e in pair.Value) {
+ int count = e.Count;
+ ThingDef thingDef = e.ThingDef;
+ ThingDef stuffDef = null;
+ EquipmentKey key = new EquipmentKey(thingDef);
+ EquipmentRecord entry = equipmentDatabase.LookupEquipmentRecord(key);
+ if (entry == null) {
+ entry = AddNonStandardScenarioEquipmentEntry(key);
+ }
+ if (entry != null) {
+ AddEquipment(entry, count);
+ }
+ else {
+ Logger.Warning(String.Format("Couldn't initialize all scenario equipment. Didn't find an equipment entry for {0} ({1})",
+ thingDef, stuffDef != null ? stuffDef.defName : "no material"));
+ }
+ }
+
+ }
+
//index = 0;
//foreach (ScenPart part in Verse.Find.Scenario.AllParts) {
// Logger.Debug(String.Format("[{0}] Replaced? {1}: {2} {3}", index, ReplacedScenarioParts.Contains(part), part.Label, String.Join(", ", part.GetSummaryListEntries("PlayerStartsWith"))));
@@ -349,10 +369,11 @@ public void ClearPawns() {
pawns.Clear();
}
public void AddPawn(CustomPawn customPawn) {
- PreloadPawnEquipment(customPawn.Pawn);
+ PreloadPawnEquipment(customPawn);
pawns.Add(customPawn);
}
- protected void PreloadPawnEquipment(Pawn pawn) {
+ protected void PreloadPawnEquipment(CustomPawn customPawn) {
+ Pawn pawn = customPawn.Pawn;
if (pawn.equipment != null) {
foreach (var e in pawn.equipment.AllEquipmentListForReading) {
if (e.Stuff != null) {
@@ -361,6 +382,27 @@ protected void PreloadPawnEquipment(Pawn pawn) {
equipmentDatabase.PreloadDefinition(e.def);
}
}
+ if (pawn.inventory != null) {
+ foreach (var e in pawn.inventory.GetDirectlyHeldThings()) {
+ if (e.Stuff != null) {
+ equipmentDatabase.PreloadDefinition(e.Stuff);
+ }
+ equipmentDatabase.PreloadDefinition(e.def);
+
+ // If the pawn is a colonist, add their inventory to the colony equipment
+ if (customPawn.Type == CustomPawnType.Colonist) {
+ EquipmentRecord entry = equipmentDatabase.LookupEquipmentRecord(new EquipmentKey(e.def, e.Stuff));
+ if (entry != null) {
+ if (e.stackCount > 1) {
+ AddEquipment(entry, e.stackCount);
+ }
+ else {
+ AddEquipment(entry);
+ }
+ }
+ }
+ }
+ }
if (pawn.apparel != null) {
foreach (var e in pawn.apparel.WornApparel) {
if (e.Stuff != null) {
diff --git a/Source/ProviderAgeLimits.cs b/Source/ProviderAgeLimits.cs
index 6aead9f..81b589e 100644
--- a/Source/ProviderAgeLimits.cs
+++ b/Source/ProviderAgeLimits.cs
@@ -3,8 +3,10 @@
using System.Linq;
using System.Reflection;
using System.Text;
+using EdB.PrepareCarefully.HarmonyPatches;
using UnityEngine;
using Verse;
+using Verse.Noise;
namespace EdB.PrepareCarefully {
@@ -14,50 +16,100 @@ public class ProviderAgeLimits {
private Dictionary minAgeLookup = new Dictionary();
private Dictionary maxAgeLookup = new Dictionary();
+ private Dictionary, int> minAgeTicksLookup = new Dictionary, int>();
+ private Dictionary, int> maxAgeTicksLookup = new Dictionary, int>();
+
public int MinAgeForPawn(Pawn pawn) {
- if (!minAgeLookup.TryGetValue(pawn.def, out int age)) {
- SimpleCurve simpleCurve = pawn.def.race.ageGenerationCurve;
- if (simpleCurve == null) {
- Logger.Warning("No age generation curve defined for " + pawn.def.defName + ". Using default age generation curve to determine minimum age.");
- simpleCurve = DefaultAgeGenerationCurve;
- if (simpleCurve == null) {
- Logger.Warning("Failed to get default age generation curve. Using default minimum age of " + DEFAULT_MIN_AGE);
- age = DEFAULT_MIN_AGE;
- }
- else {
- age = Mathf.CeilToInt(pawn.def.race.lifeExpectancy * simpleCurve.First().x);
+ // TODO: This probably doesn't work for alien races
+ if (!minAgeTicksLookup.TryGetValue(ValueTuple.Create(pawn.def, pawn.DevelopmentalStage), out int years)) {
+ float min = float.MaxValue;
+ foreach (var a in pawn.def.race.lifeStageAges) {
+ if (a.def.developmentalStage == pawn.DevelopmentalStage && a.minAge < min) {
+ min = a.minAge;
}
}
- else {
- CurvePoint point = simpleCurve.First();
- age = (int)point.x;
+ if (min == float.MaxValue) {
+ min = 0;
}
- minAgeLookup.Add(pawn.def, age);
+ int value = Mathf.FloorToInt(min);
+ minAgeTicksLookup.Add(ValueTuple.Create(pawn.def, pawn.DevelopmentalStage), value);
+ //Logger.Debug("Min age for " + pawn.DevelopmentalStage + " = " + value);
+ return value;
+ }
+ else {
+ return years;
}
- return age;
+
+ //if (!minAgeLookup.TryGetValue(pawn.def, out int age)) {
+ // SimpleCurve simpleCurve = pawn.def.race.ageGenerationCurve;
+ // if (simpleCurve == null) {
+ // Logger.Warning("No age generation curve defined for " + pawn.def.defName + ". Using default age generation curve to determine minimum age.");
+ // simpleCurve = DefaultAgeGenerationCurve;
+ // if (simpleCurve == null) {
+ // Logger.Warning("Failed to get default age generation curve. Using default minimum age of " + DEFAULT_MIN_AGE);
+ // age = DEFAULT_MIN_AGE;
+ // }
+ // else {
+ // age = Mathf.CeilToInt(pawn.def.race.lifeExpectancy * simpleCurve.First().x);
+ // }
+ // }
+ // else {
+ // CurvePoint point = simpleCurve.First();
+ // age = (int)point.x;
+ // }
+ // minAgeLookup.Add(pawn.def, age);
+ //}
+ //return age;
}
public int MaxAgeForPawn(Pawn pawn) {
- if (!maxAgeLookup.TryGetValue(pawn.def, out int age)) {
- SimpleCurve simpleCurve = pawn.def.race.ageGenerationCurve;
- if (simpleCurve == null) {
- Logger.Warning("No age generation curve defined for " + pawn.def.defName + ". Using default age generation curve to determine maximum age.");
- simpleCurve = DefaultAgeGenerationCurve;
- if (simpleCurve == null) {
- Logger.Warning("Failed to get default age generation curve. Using default maximum age of " + DEFAULT_MAX_AGE);
- age = DEFAULT_MAX_AGE;
- }
- else {
- age = Mathf.CeilToInt(pawn.def.race.lifeExpectancy * simpleCurve.Last().x);
+ // TODO: This probably doesn't work for alien races
+ if (!maxAgeTicksLookup.TryGetValue(ValueTuple.Create(pawn.def, pawn.DevelopmentalStage), out int years)) {
+ float max = float.MinValue;
+ int count = pawn.def.race.lifeStageAges.Count;
+ float previousValue = float.MinValue;
+ for(int i=count-1; i>=0; i--) {
+ var a = pawn.def.race.lifeStageAges[i];
+ if (a.def.developmentalStage == pawn.DevelopmentalStage) {
+ max = previousValue;
+ break;
}
+ previousValue = a.minAge;
+ }
+ if (max == float.MinValue) {
+ max = pawn.def.race.lifeExpectancy * 1.5f;
}
else {
- CurvePoint point = simpleCurve.Last();
- age = (int)(point.x * 1.2f);
+ max--;
}
- maxAgeLookup.Add(pawn.def, age);
+ int value = Mathf.FloorToInt(max);
+ maxAgeTicksLookup.Add(ValueTuple.Create(pawn.def, pawn.DevelopmentalStage), value);
+ //Logger.Debug("Max age for " + pawn.DevelopmentalStage + " " + pawn.def.defName + " = " + value);
+ return value;
+ }
+ else {
+ return years;
}
- return age;
+ //if (!maxAgeLookup.TryGetValue(pawn.def, out int age)) {
+ // SimpleCurve simpleCurve = pawn.def.race.ageGenerationCurve;
+ // if (simpleCurve == null) {
+ // Logger.Warning("No age generation curve defined for " + pawn.def.defName + ". Using default age generation curve to determine maximum age.");
+ // simpleCurve = DefaultAgeGenerationCurve;
+ // if (simpleCurve == null) {
+ // Logger.Warning("Failed to get default age generation curve. Using default maximum age of " + DEFAULT_MAX_AGE);
+ // age = DEFAULT_MAX_AGE;
+ // }
+ // else {
+ // age = Mathf.CeilToInt(pawn.def.race.lifeExpectancy * simpleCurve.Last().x);
+ // }
+ // }
+ // else {
+ // CurvePoint point = simpleCurve.Last();
+ // age = (int)(point.x * 1.2f);
+ // }
+ // maxAgeLookup.Add(pawn.def, age);
+ //}
+ //return age;
}
protected SimpleCurve DefaultAgeGenerationCurve {
diff --git a/Source/ProviderAlienRaces.cs b/Source/ProviderAlienRaces.cs
index e540a5c..012cc56 100644
--- a/Source/ProviderAlienRaces.cs
+++ b/Source/ProviderAlienRaces.cs
@@ -30,13 +30,18 @@ public AlienRace GetAlienRace(ThingDef def) {
}
else {
if (IsAlienRace(def)) {
+ //Logger.Debug(def.defName + " is an alien race");
result = InitializeAlienRace(def);
if (result != null) {
lookup.Add(def, result);
}
+ else {
+ Logger.Debug("Failed to initialize " + def.defName + " alien race");
+ }
return result;
}
else {
+ //Logger.Debug(def.defName + " is not an alien race");
return null;
}
}
@@ -118,7 +123,6 @@ protected ColorGenerator FindSecondaryColorGenerator(ThingDef raceDef, object al
protected ColorGenerator FindColorGenerator(ThingDef raceDef, object alienPartGeneratorObject, string channelName, string generatorFieldName) {
object colorChannelsObject = GetFieldValue(raceDef, alienPartGeneratorObject, "colorChannels", true);
if (colorChannelsObject == null) {
- Logger.Warning("didn't find colorChannels field");
return null;
}
System.Collections.IList colorChannelList = colorChannelsObject as System.Collections.IList;
@@ -136,25 +140,34 @@ protected ColorGenerator FindColorGenerator(ThingDef raceDef, object alienPartGe
if (foundGenerator == null) {
return null;
}
- return GetFieldValue(raceDef, foundGenerator, generatorFieldName, true) as ColorGenerator;
+ System.Collections.IList colorChannelGeneratorCategoryList = GetFieldValueAsCollection(raceDef, foundGenerator, "entries") as System.Collections.IList;
+ if (colorChannelGeneratorCategoryList == null || colorChannelGeneratorCategoryList.Count == 0) {
+ return null;
+ }
+ object colorChannelGeneratorCategory = colorChannelGeneratorCategoryList[0];
+ return GetFieldValue(raceDef, colorChannelGeneratorCategory, generatorFieldName, true) as ColorGenerator;
}
protected AlienRace InitializeAlienRace(ThingDef raceDef) {
try {
- object alienRaceObject = GetFieldValue(raceDef, raceDef, "alienRace");
- if (alienRaceObject == null) {
+ object alienSettingsObject = GetFieldValue(raceDef, raceDef, "alienRace");
+ if (alienSettingsObject == null) {
+ Logger.Debug("Didn't find AlienSettings object in ThingDef_AlienRace.alienRace field");
return null;
}
- object generalSettingsObject = GetFieldValue(raceDef, alienRaceObject, "generalSettings");
+ object generalSettingsObject = GetFieldValue(raceDef, alienSettingsObject, "generalSettings");
if (generalSettingsObject == null) {
+ Logger.Debug("Didn't find GeneralSettings object in ThingDef_AlienRace.AlienSettings.generalSettings field");
return null;
}
object alienPartGeneratorObject = GetFieldValue(raceDef, generalSettingsObject, "alienPartGenerator");
if (alienPartGeneratorObject == null) {
+ Logger.Debug("Didn't find AlienPartGenerator object in GeneralSettings.alienPartGenerator field");
return null;
}
- System.Collections.ICollection graphicPathsCollection = GetFieldValueAsCollection(raceDef, alienRaceObject, "graphicPaths");
- if (graphicPathsCollection == null) {
+ object graphicsPathsObject = GetFieldValue(raceDef, alienSettingsObject, "graphicPaths");
+ if (graphicsPathsObject == null) {
+ Logger.Debug("Didn't find GraphicsPaths object in ThingDef_AlienRace.graphicPaths field");
return null;
}
@@ -170,6 +183,7 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
}
*/
+
// We have enough to start putting together the result object, so we instantiate it now.
AlienRace result = new AlienRace();
result.ThingDef = raceDef;
@@ -183,7 +197,7 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
result.MinAgeForAdulthood = minAgeForAdulthood;
// Get the list of body types.
- System.Collections.ICollection alienBodyTypesCollection = GetFieldValueAsCollection(raceDef, alienPartGeneratorObject, "alienbodytypes");
+ System.Collections.ICollection alienBodyTypesCollection = GetFieldValueAsCollection(raceDef, alienPartGeneratorObject, "bodyTypes");
if (alienBodyTypesCollection == null) {
return null;
}
@@ -196,56 +210,25 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
}
}
}
- else {
- //Logger.Debug(" none");
- }
//Logger.Debug($"Body types for alien race {raceDef.defName}: {string.Join(", ", bodyTypes.Select(b => b.defName + ", " + b.LabelCap))}");
result.BodyTypes = bodyTypes;
- // Determine if the alien races uses gender-specific heads.
- bool? useGenderedHeads = GetFieldValueAsBool(raceDef, alienPartGeneratorObject, "useGenderedHeads");
- if (useGenderedHeads == null) {
+ // Get the list of head types.
+ System.Collections.ICollection alienHeadTypesCollection = GetFieldValueAsCollection(raceDef, alienPartGeneratorObject, "headTypes");
+ if (alienHeadTypesCollection == null) {
+ Logger.Debug("Didn't find List object in AlienPartGenerator.headTypes field");
return null;
}
- result.GenderSpecificHeads = useGenderedHeads.Value;
-
- // Get the list of crown types.
- System.Collections.ICollection alienCrownTypesCollection = GetFieldValueAsCollection(raceDef, alienPartGeneratorObject, "aliencrowntypes");
- if (alienCrownTypesCollection == null) {
- return null;
- }
- List crownTypes = new List();
- //Logger.Debug("Crown Types for " + raceDef.defName + ":");
- if (alienCrownTypesCollection.Count > 0) {
- foreach (object o in alienCrownTypesCollection) {
- string crownTypeString = o as string;
- if (crownTypeString != null) {
- crownTypes.Add(crownTypeString);
- //Logger.Debug(" " + crownTypeString);
- }
- }
- }
- result.CrownTypes = crownTypes;
-
- // Go through the graphics paths and find the heads path.
- // TODO: What is this?
- string graphicsPathForHeads = null;
- string graphicsPathForBodyTypes = null;
- foreach (var graphicsPath in graphicPathsCollection) {
- System.Collections.ICollection lifeStageCollection = GetFieldValueAsCollection(raceDef, graphicsPath, "lifeStageDefs");
- if (lifeStageCollection == null || lifeStageCollection.Count == 0) {
- string headsPath = GetFieldValueAsString(raceDef, graphicsPath, "head");
- string bodyTypesPath = GetFieldValueAsString(raceDef, graphicsPath, "body");
- if (headsPath != null) {
- graphicsPathForHeads = headsPath;
- }
- if (bodyTypesPath != null) {
- graphicsPathForBodyTypes = bodyTypesPath;
+ List headTypes = new List();
+ if (alienHeadTypesCollection.Count > 0) {
+ foreach (object o in alienHeadTypesCollection) {
+ if (o.GetType() == typeof(HeadTypeDef)) {
+ HeadTypeDef def = o as HeadTypeDef;
+ headTypes.Add((HeadTypeDef)o);
}
}
}
- result.GraphicsPathForHeads = graphicsPathForHeads;
- result.GraphicsPathForBodyTypes = graphicsPathForBodyTypes;
+ result.HeadTypes = headTypes;
// Figure out colors.
ColorGenerator primaryGenerator = FindPrimarySkinColorGenerator(raceDef, alienPartGeneratorObject);
@@ -275,7 +258,7 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
}
// Style settings
- object styleSettingsValue = GetFieldValue(raceDef, alienRaceObject, "styleSettings", true);
+ object styleSettingsValue = GetFieldValue(raceDef, alienSettingsObject, "styleSettings", true);
result.HasHair = true;
result.HasBeards = true;
@@ -333,7 +316,7 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
}
// Apparel properties.
- object restrictionSettingsValue = GetFieldValue(raceDef, alienRaceObject, "raceRestriction", true);
+ object restrictionSettingsValue = GetFieldValue(raceDef, alienSettingsObject, "raceRestriction", true);
result.RaceSpecificApparelOnly = false;
result.RaceSpecificApparel = new HashSet();
result.AllowedApparel = new HashSet();
@@ -406,7 +389,7 @@ protected AlienRace InitializeAlienRace(ThingDef raceDef) {
return result;
}
catch (Exception e) {
- throw new InitializationException("Failed to initialize an alien race: " + raceDef.defName, e);
+ throw new InitializationException("Exception when trying to initialize an alien race: " + raceDef.defName, e);
}
}
protected string ParseAddonName(string path) {
diff --git a/Source/ProviderApparel.cs b/Source/ProviderApparel.cs
index 7190036..b9504e0 100644
--- a/Source/ProviderApparel.cs
+++ b/Source/ProviderApparel.cs
@@ -10,38 +10,38 @@
namespace EdB.PrepareCarefully {
public class ProviderApparel {
- protected Dictionary apparelLookup = new Dictionary();
+ protected Dictionary, OptionsApparel> apparelLookup = new Dictionary, OptionsApparel>();
protected OptionsApparel humanlikeApparel;
protected OptionsApparel noApparel = new OptionsApparel();
public ProviderAlienRaces AlienRaceProvider {
get; set;
}
public List GetApparel(CustomPawn pawn, PawnLayer layer) {
- return GetApparel(pawn.Pawn.def, layer);
+ return GetApparel(pawn.Pawn.def, pawn.Pawn.DevelopmentalStage, layer);
}
- public List GetApparel(ThingDef raceDef, PawnLayer layer) {
- OptionsApparel apparel = GetApparelForRace(raceDef);
+ public List GetApparel(ThingDef raceDef, DevelopmentalStage stage, PawnLayer layer) {
+ OptionsApparel apparel = GetApparelForRaceAndDevelopmentalStage(raceDef, stage);
return apparel.GetApparel(layer);
}
public OptionsApparel GetApparelForRace(CustomPawn pawn) {
- return GetApparelForRace(pawn.Pawn.def);
+ return GetApparelForRaceAndDevelopmentalStage(pawn.Pawn.def, pawn.Pawn.DevelopmentalStage);
}
- public OptionsApparel GetApparelForRace(ThingDef raceDef) {
+ public OptionsApparel GetApparelForRaceAndDevelopmentalStage(ThingDef raceDef, DevelopmentalStage stage) {
OptionsApparel apparel;
- if (apparelLookup.TryGetValue(raceDef, out apparel)) {
+ if (apparelLookup.TryGetValue(ValueTuple.Create(raceDef, stage), out apparel)) {
return apparel;
}
- apparel = InitializeApparel(raceDef);
+ apparel = InitializeApparel(raceDef, stage);
if (apparel == null) {
if (raceDef != ThingDefOf.Human) {
- return GetApparelForRace(ThingDefOf.Human);
+ return GetApparelForRaceAndDevelopmentalStage(ThingDefOf.Human, stage);
}
else {
return null;
}
}
else {
- apparelLookup.Add(raceDef, apparel);
+ apparelLookup.Add(ValueTuple.Create(raceDef, stage), apparel);
return apparel;
}
}
@@ -65,10 +65,10 @@ protected void AddApparelToOptions(OptionsApparel options, ThingDef def) {
options.Add(layer, def);
}
}
- protected OptionsApparel InitializeApparel(ThingDef raceDef) {
+ protected OptionsApparel InitializeApparel(ThingDef raceDef, DevelopmentalStage stage) {
AlienRace alienRace = AlienRaceProvider.GetAlienRace(raceDef);
if (alienRace == null) {
- return HumanlikeApparel;
+ return HumanlikeApparelForDevelopmentStage(stage);
}
OptionsApparel result = new OptionsApparel();
HashSet addedAlready = new HashSet();
@@ -82,7 +82,7 @@ protected OptionsApparel InitializeApparel(ThingDef raceDef) {
// Even if we're only allowed to use race-specific apparel, we're also allowed to use anything in the allowed list.
if (alienRace.RaceSpecificApparelOnly) {
HashSet allowed = alienRace.AllowedApparel ?? new HashSet();
- foreach (var def in HumanlikeApparel.AllApparel ?? Enumerable.Empty()) {
+ foreach (var def in HumanlikeApparelForDevelopmentStage(stage).AllApparel ?? Enumerable.Empty()) {
if (allowed.Contains(def.defName) && !addedAlready.Contains(def.defName)) {
AddApparelToOptions(result, def);
addedAlready.Add(def.defName);
@@ -92,7 +92,7 @@ protected OptionsApparel InitializeApparel(ThingDef raceDef) {
// Even if we're allowed to use more than just race-specific apparel, we can't use anything in the disallowed list.
else {
HashSet disallowed = alienRace.DisallowedApparel ?? new HashSet();
- foreach (var def in HumanlikeApparel.AllApparel ?? Enumerable.Empty()) {
+ foreach (var def in HumanlikeApparelForDevelopmentStage(stage).AllApparel ?? Enumerable.Empty()) {
if (!addedAlready.Contains(def.defName) && !disallowed.Contains(def.defName)) {
AddApparelToOptions(result, def);
addedAlready.Add(def.defName);
@@ -102,15 +102,15 @@ protected OptionsApparel InitializeApparel(ThingDef raceDef) {
result.Sort();
return result;
}
- protected OptionsApparel HumanlikeApparel {
- get {
- if (humanlikeApparel == null) {
- humanlikeApparel = InitializeHumanlikeApparel();
- }
- return humanlikeApparel;
+
+ protected OptionsApparel HumanlikeApparelForDevelopmentStage(DevelopmentalStage stage) {
+ if (apparelLookup.TryGetValue(ValueTuple.Create(ThingDefOf.Human, stage), out var options)) {
+ return options;
}
+ return InitializeHumanlikeApparel(stage);
}
- protected OptionsApparel InitializeHumanlikeApparel() {
+
+ protected OptionsApparel InitializeHumanlikeApparel(DevelopmentalStage stage) {
HashSet nonHumanApparel = new HashSet();
IEnumerable alienRaces = DefDatabase.AllDefs.Where((ThingDef def) => {
return def.race != null && ProviderAlienRaces.IsAlienRace(def);
@@ -134,6 +134,9 @@ protected OptionsApparel InitializeHumanlikeApparel() {
if (apparelDef.apparel == null) {
continue;
}
+ if (!apparelDef.apparel.developmentalStageFilter.Has(stage)) {
+ continue;
+ }
if (!nonHumanApparel.Contains(apparelDef.defName)) {
AddApparelToOptions(result, apparelDef);
}
diff --git a/Source/ProviderBackstories.cs b/Source/ProviderBackstories.cs
index 3b8127a..cc47b82 100644
--- a/Source/ProviderBackstories.cs
+++ b/Source/ProviderBackstories.cs
@@ -5,55 +5,57 @@
using Verse;
namespace EdB.PrepareCarefully {
public class ProviderBackstories {
- protected List childhoodBackstories = new List();
- protected List adulthoodBackstories = new List();
- protected List sortedChildhoodBackstories;
- protected List sortedAdulthoodBackstories;
+ protected List childhoodBackstories = new List();
+ protected List adulthoodBackstories = new List();
+ protected List sortedChildhoodBackstories;
+ protected List sortedAdulthoodBackstories;
- protected Dictionary> childhoodBackstoryLookup = new Dictionary>();
- protected Dictionary> adulthoodBackstoryLookup = new Dictionary>();
- protected Dictionary> backstoryHashSetLookup = new Dictionary>();
+ protected Dictionary> childhoodBackstoryLookup = new Dictionary