diff --git a/Source/Genes/Hive/Helpers/HiveBirthLogic.cs b/Source/Genes/Hive/Helpers/HiveBirthLogic.cs new file mode 100644 index 0000000..ef6cc21 --- /dev/null +++ b/Source/Genes/Hive/Helpers/HiveBirthLogic.cs @@ -0,0 +1,134 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace RJW_Genes +{ + public class HiveBirthLogic + { + /// + /// Central function for the Hive-Birth logic used in Patches. + /// *Only* run this, if the pawn has a queen parent (either as mother/father, or as implanter in case of egg-logic). + /// Covers the following behavior: + /// 1. look up the Defs for the mother and HiveOffspringChances (or defaults) + /// 2. If there is no drone involved, default to worker + /// 3. Roll a random dice + /// 3.1 Make a queen + /// 3.2 Make a drone + /// 3.3 Make a worker + /// + /// The pawn born, that maybe becomes a hive-xenotype. + /// whether there was a drone parent involved + public static void ManageHiveBirth(Pawn pawn, bool hasDroneParent = false) + { + XenotypeDef queenDef = TryFindParentQueenXenotype(pawn); + HiveOffspringChanceDef hiveOffspringChanceDef = HiveUtility.LookupHiveInheritanceChances(queenDef); + + // Case 1: Mother is Queen, Father is something else. Produce Worker. + if (!hasDroneParent) + { + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} was born as a worker, as it did not have Drone Father ({100}% chance)"); + MakeWorker(pawn, queenDef); + } + // Case 2: Mother is Queen, Father is drone. Apply xenotype as per chance. + else + { + double roll = (new Random()).NextDouble(); + // Case 2.a: New Queen born + if (roll < hiveOffspringChanceDef.queenChance) + { + pawn.genes.SetXenotype(queenDef); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new queen with xenotype {queenDef.defName} ({hiveOffspringChanceDef.queenChance * 100}% chance,rolled {roll})"); + // TODO: Make a letter ? + } + // Case 2.b: New Drone born + else if (roll < hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) + { + XenotypeDef droneDef = TryFindParentDroneXenotype(pawn); + pawn.genes.SetXenotype(droneDef); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new drone with xenotype {droneDef.defName} ({(hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) * 100}% chance,rolled {roll}))"); + } + // Case 2.c: Worker + else + { + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a worker ({(hiveOffspringChanceDef.workerChance) * 100}% chance,rolled {roll}))"); + MakeWorker(pawn, queenDef); + } + } + } + + + /// + /// Turns a given pawn into a worker, by looking up the relevant genes as per queen. + /// + /// If the queen xenotype has no mapping, the "rjw_genes_default_worker_xenotype" are used instead. + /// The genes are added as endogenes, so the worker can still become a xenotype. + /// + /// The pawn for which the genes are added. + /// The xenotype of the queen, used for lookup. + private static void MakeWorker(Pawn pawnTobeWorker, XenotypeDef queenDef) + { + if (pawnTobeWorker == null) + return; + + var mappings = HiveUtility.GetQueenWorkerMappings(); + + var genes = mappings.TryGetValue(queenDef, HiveUtility.LookupDefaultWorkerGenes()); + + foreach (var gene in genes) + pawnTobeWorker.genes.AddGene(gene, false); + + } + + /// + /// Looks up if there is a Xenotype with Drone-Gene for the pawns parents. + /// This is to account that maybe father or mother are the drone (instead of hardcoding things for father). + /// If both are drones, the mothers is returned. + /// + /// The pawn for whichs parent the xenotypes is looked up. + /// The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred. + public static XenotypeDef TryFindParentDroneXenotype(Pawn pawn) + { + if (pawn == null) + return null; + + var motherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetMother()); + var fatherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetFather()); + + if (motherXenotype != null) + return motherXenotype; + if (fatherXenotype != null) + return fatherXenotype; + + return null; + } + + + /// + /// Looks up if there is a Xenotype with Queen-Gene for the pawns parents. + /// This is to account that maybe father or mother are the queen (instead of hardcoding things for father). + /// If both are queens, the mothers is returned. + /// + /// The pawn for whichs parent the xenotypes is looked up. + /// The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred. + public static XenotypeDef TryFindParentQueenXenotype(Pawn pawn) + { + if (pawn == null) + return null; + + var motherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetMother()); + var fatherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetFather()); + + if (motherXenotype != null) + return motherXenotype; + if (fatherXenotype != null) + return fatherXenotype; + + return null; + } + } +} diff --git a/Source/Genes/Hive/Helpers/HiveUtility.cs b/Source/Genes/Hive/Helpers/HiveUtility.cs index db65fb6..c7d262d 100644 --- a/Source/Genes/Hive/Helpers/HiveUtility.cs +++ b/Source/Genes/Hive/Helpers/HiveUtility.cs @@ -224,5 +224,6 @@ namespace RJW_Genes return offspringChanceDefs.FirstOrFallback(t => t.queenXenotype == queenDef.defName, LookupDefaultHiveInheritanceChances()); } + } } diff --git a/Source/Genes/Hive/Patches/Patch_BirthOutcome_SetHiveGenes.cs b/Source/Genes/Hive/Patches/Patch_BirthOutcome_SetHiveGenes.cs index c075cc8..7bdf206 100644 --- a/Source/Genes/Hive/Patches/Patch_BirthOutcome_SetHiveGenes.cs +++ b/Source/Genes/Hive/Patches/Patch_BirthOutcome_SetHiveGenes.cs @@ -34,116 +34,20 @@ namespace RJW_Genes Pawn pawn = (Pawn)__result; // Important: Not all pawns have mother/father. Some Pawns are born in Growth-Vats or born from mod. - bool hasQueenParent = TryFindParentQueenXenotype(pawn) != null; - bool hasDroneParent = TryFindParentDroneXenotype(pawn) != null; + bool hasQueenParent = HiveBirthLogic.TryFindParentQueenXenotype(pawn) != null; + bool hasDroneParent = HiveBirthLogic.TryFindParentDroneXenotype(pawn) != null; if (hasQueenParent) { if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"PostFix PregnancyUtility::ApplyBirthOutcome - Checking Hive Inheritance because {pawn} has a queen parent."); - XenotypeDef queenDef = TryFindParentQueenXenotype(pawn); - HiveOffspringChanceDef hiveOffspringChanceDef = HiveUtility.LookupHiveInheritanceChances(queenDef); - - // Case 1: Mother is Queen, Father is something else. Produce Worker. - if (!hasDroneParent) - { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} was born as a worker, as it did not have Drone Father ({100}% chance)"); - MakeWorker(pawn, queenDef); - } - // Case 2: Mother is Queen, Father is drone. Apply xenotype as per chance. - else - { - double roll = (new Random()).NextDouble(); - // Case 2.a: New Queen born - if (roll < hiveOffspringChanceDef.queenChance) - { - pawn.genes.SetXenotype(queenDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new queen with xenotype {queenDef.defName} ({hiveOffspringChanceDef.queenChance * 100}% chance,rolled {roll})"); - // TODO: Make a letter ? - } - // Case 2.b: New Drone born - else if (roll < hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) - { - XenotypeDef droneDef = TryFindParentDroneXenotype(pawn); - pawn.genes.SetXenotype(droneDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new drone with xenotype {droneDef.defName} ({(hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) * 100}% chance,rolled {roll}))"); - } - // Case 2.c: Worker - else { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a worker ({(hiveOffspringChanceDef.workerChance) * 100}% chance,rolled {roll}))"); - MakeWorker(pawn, queenDef); - } - } + HiveBirthLogic.ManageHiveBirth(pawn, hasDroneParent); + } + else + { + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Ignoring Postfix PregnancyUtility::ApplyBirthOutcome - No Quene Parent - Doing Nothing"); } } - /// - /// Turns a given pawn into a worker, by looking up the relevant genes as per queen. - /// - /// If the queen xenotype has no mapping, the "rjw_genes_default_worker_xenotype" are used instead. - /// The genes are added as endogenes, so the worker can still become a xenotype. - /// - /// The pawn for which the genes are added. - /// The xenotype of the queen, used for lookup. - private static void MakeWorker(Pawn pawnTobeWorker, XenotypeDef queenDef) - { - if (pawnTobeWorker == null) - return; - - var mappings = HiveUtility.GetQueenWorkerMappings(); - - var genes = mappings.TryGetValue(queenDef, HiveUtility.LookupDefaultWorkerGenes()); - - foreach (var gene in genes) - pawnTobeWorker.genes.AddGene(gene, false); - - } - - /// - /// Looks up if there is a Xenotype with Drone-Gene for the pawns parents. - /// This is to account that maybe father or mother are the drone (instead of hardcoding things for father). - /// If both are drones, the mothers is returned. - /// - /// The pawn for whichs parent the xenotypes is looked up. - /// The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred. - private static XenotypeDef TryFindParentDroneXenotype(Pawn pawn) - { - if (pawn == null) - return null; - - var motherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetMother()); - var fatherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetFather()); - - if (motherXenotype != null) - return motherXenotype; - if (fatherXenotype != null) - return fatherXenotype; - - return null; - } - - - /// - /// Looks up if there is a Xenotype with Queen-Gene for the pawns parents. - /// This is to account that maybe father or mother are the queen (instead of hardcoding things for father). - /// If both are queens, the mothers is returned. - /// - /// The pawn for whichs parent the xenotypes is looked up. - /// The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred. - private static XenotypeDef TryFindParentQueenXenotype(Pawn pawn) - { - if (pawn == null) - return null; - - var motherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetMother()); - var fatherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetFather()); - - if (motherXenotype != null) - return motherXenotype; - if (fatherXenotype != null) - return fatherXenotype; - - return null; - } } } diff --git a/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs b/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs index e65986e..c864732 100644 --- a/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs +++ b/Source/Genes/Hive/Patches/Patch_InsectEggs_BirthBaby_SetHiveGenes.cs @@ -14,6 +14,7 @@ namespace RJW_Genes /// Patches the method `ProcessHumanLikeInsectEgg` from `Hediff_InsectEgg`. /// /// The 'ProcessHumanLikeInsectEgg' returns the finished baby, for which we alter the pawn according to our xenotypes. + /// Note: This covers Insect-Egg Pregnancies only, and there is a (very similar) class `Patch_BirthOutCome_SetHiveGenes.cs` that handles normal pregnancies /// [HarmonyPatch(typeof(Hediff_InsectEgg), "ProcessHumanLikeInsectEgg")] @@ -24,130 +25,29 @@ namespace RJW_Genes [HarmonyPostfix] static void HandleHiveBasedInheritance(ref Thing __result) { - + // Check: Was the born thing a pawn? if (__result == null || !(__result is Pawn)) { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message("There was a birth of something non-human - not entering logic for queen-drone-xenotype inheritance."); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message("There was a birth of something non-human - not entering logic for queen-drone-xenotype inheritance."); return; } Pawn pawn = (Pawn)__result; // Important: Not all pawns have mother/father. Some Pawns are born in Growth-Vats or born from mod. - bool hasQueenParent = TryFindParentQueenXenotype(pawn) != null; - bool hasDroneParent = TryFindParentDroneXenotype(pawn) != null; + bool hasQueenParent = HiveBirthLogic.TryFindParentQueenXenotype(pawn) != null; + bool hasDroneParent = HiveBirthLogic.TryFindParentDroneXenotype(pawn) != null; if (hasQueenParent) { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"PostFix PregnancyUtility::ApplyBirthOutcome - Checking Hive Inheritance because {pawn} has a queen parent."); - - XenotypeDef queenDef = TryFindParentQueenXenotype(pawn); - HiveOffspringChanceDef hiveOffspringChanceDef = HiveUtility.LookupHiveInheritanceChances(queenDef); - - // Case 1: Mother is Queen, Father is something else. Produce Worker. - if (!hasDroneParent) - { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} was born as a worker, as it did not have Drone Father ({100}% chance)"); - MakeWorker(pawn, queenDef); - } - // Case 2: Mother is Queen, Father is drone. Apply xenotype as per chance. - else - { - double roll = (new Random()).NextDouble(); - // Case 2.a: New Queen born - if (roll < hiveOffspringChanceDef.queenChance) - { - pawn.genes.SetXenotype(queenDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new queen with xenotype {queenDef.defName} ({hiveOffspringChanceDef.queenChance * 100}% chance,rolled {roll})"); - // TODO: Make a letter ? - } - // Case 2.b: New Drone born - else if (roll < hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) - { - XenotypeDef droneDef = TryFindParentDroneXenotype(pawn); - pawn.genes.SetXenotype(droneDef); - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new drone with xenotype {droneDef.defName} ({(hiveOffspringChanceDef.droneChance + hiveOffspringChanceDef.queenChance) * 100}% chance,rolled {roll}))"); - } - // Case 2.c: Worker - else { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a worker ({(hiveOffspringChanceDef.workerChance) * 100}% chance,rolled {roll}))"); - MakeWorker(pawn, queenDef); - } - } + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"PostFix Hediff_InsectEgg::ProcessHumanLikeInsectEgg - Checking Hive Inheritance because {pawn} has a queen parent."); + HiveBirthLogic.ManageHiveBirth(pawn, hasDroneParent); } else { - if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message("There was an egg-birth without a (detected) queen-parent"); + if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Ignoring Postfix Hediff_InsectEgg::ProcessHumanLikeInsectEgg - No Queen Parent - No Action."); } } - /// - /// Turns a given pawn into a worker, by looking up the relevant genes as per queen. - /// - /// If the queen xenotype has no mapping, the "rjw_genes_default_worker_xenotype" are used instead. - /// The genes are added as endogenes, so the worker can still become a xenotype. - /// - /// The pawn for which the genes are added. - /// The xenotype of the queen, used for lookup. - private static void MakeWorker(Pawn pawnTobeWorker, XenotypeDef queenDef) - { - if (pawnTobeWorker == null) - return; - - var mappings = HiveUtility.GetQueenWorkerMappings(); - - var genes = mappings.TryGetValue(queenDef, HiveUtility.LookupDefaultWorkerGenes()); - - foreach (var gene in genes) - pawnTobeWorker.genes.AddGene(gene, false); - - } - - /// - /// Looks up if there is a Xenotype with Drone-Gene for the pawns parents. - /// This is to account that maybe father or mother are the drone (instead of hardcoding things for father). - /// If both are drones, the mothers is returned. - /// - /// The pawn for whichs parent the xenotypes is looked up. - /// The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred. - private static XenotypeDef TryFindParentDroneXenotype(Pawn pawn) - { - if (pawn == null) - return null; - - var motherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetMother()); - var fatherXenotype = HiveUtility.TryGetDroneXenotype(pawn.GetFather()); - - if (motherXenotype != null) - return motherXenotype; - if (fatherXenotype != null) - return fatherXenotype; - - return null; - } - - - /// - /// Looks up if there is a Xenotype with Queen-Gene for the pawns parents. - /// This is to account that maybe father or mother are the queen (instead of hardcoding things for father). - /// If both are queens, the mothers is returned. - /// - /// The pawn for whichs parent the xenotypes is looked up. - /// The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred. - private static XenotypeDef TryFindParentQueenXenotype(Pawn pawn) - { - if (pawn == null) - return null; - - var motherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetMother()); - var fatherXenotype = HiveUtility.TryGetQueenXenotype(pawn.GetFather()); - - if (motherXenotype != null) - return motherXenotype; - if (fatherXenotype != null) - return fatherXenotype; - - return null; - } } } diff --git a/Source/Rjw-Genes.csproj b/Source/Rjw-Genes.csproj index ff8360b..bbbe0c9 100644 --- a/Source/Rjw-Genes.csproj +++ b/Source/Rjw-Genes.csproj @@ -47,6 +47,7 @@ +