Compare commits

..

No commits in common. "8605a09941c75cb96a9fef7fc2249885092929cb" and "677786190379e3fbaf0b45d2fb90bb62b902569f" have entirely different histories.

23 changed files with 28 additions and 1067 deletions

View file

@ -15,22 +15,6 @@ Fixes:
- Cockeater now leaves a bite wound!
- Pythokin-Patch checks for Licentialabs (#30)
**Queen & Caste Logic**
There are 3 genes revolting around a new, hopefully flexible insect-caste system. Queens, Drones and Workers. These reproduce either through normal sex, or can utilize the insect birth once [this PR](https://gitgud.io/Ed86/rjw/-/merge_requests/266) has been merged in.
In general, the logic is the following:
- A queen can have sex with anyone. If the partner was a drone, there is chance for the baby to become a queen, drone or worker.
- If the partner of the queen was not a drone, the baby will be a worker.
- If the drone didn't mate with a queen but someone else, normal inheritance happens
- The assignemnt is done by xenotypes for queen and drones. The baby will get all xenogenes of their parents xenotypes.
- For workers, every queen can have a set of genes for their workers defined in [a special def](./Common/Defs/QueenWorkerMappingDefs/QueenWorkerMappingDefs_base.xml). These will be added as endogenes, so that pawns can still become xenotypes.
- There is a default set for worker genes, making mentally dumb, sterile and servile pawns.
I am not sure if I want to have a specific mapping defining that Queen can only mate with certain Drones, let me know how you feel about it.
*Queens can be male*. I just used the female-term, but implementation is gender-neutral.
ToDo:
- Icons: Cocoon, Spelopede Spawn

View file

@ -8,7 +8,7 @@
<stunTargetWhileCasting>true</stunTargetWhileCasting>
<displayGizmoWhileUndrafted>true</displayGizmoWhileUndrafted>
<disableGizmoWhileUndrafted>false</disableGizmoWhileUndrafted>
<statBases>
<statBases>
<Ability_Duration>5</Ability_Duration>
</statBases>
<warmupMote>Mote_CoagulateStencil</warmupMote>

View file

@ -1,134 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<GeneDef>
<defName>rjw_genes_queen</defName>
<label>Hive Queen</label>
<labelShortAdj>queen</labelShortAdj>
<description>This gene represents the royal caste amongst its xenotype. Children of a queen are usually born as sterile workers, unless the father was a drone. Having multiple (adult) queens leads to intense rivalry and can throw the whole colony into chaos!</description>
<iconPath>Things/Mote/Heart</iconPath>
<displayOrderInCategory>1</displayOrderInCategory>
<displayCategory>rjw_genes_hive</displayCategory>
<statOffsets>
<PsychicSensitivity>0.5</PsychicSensitivity>
<MeditationFocusGain>0.25</MeditationFocusGain>
</statOffsets>
<conditionalStatAffecters>
<li Class="RJW_Genes.ConditionalStatAffecter_MultipleQueens">
<statFactors>
<MoveSpeed>0.7</MoveSpeed>
</statFactors>
<statOffsets>
<WorkSpeedGlobal>-0.5</WorkSpeedGlobal>
</statOffsets>
</li>
<li Class="RJW_Genes.ConditionalStatAffecter_QueenCloseBy">
<statFactors>
<MoveSpeed>0.4</MoveSpeed>
<WorkSpeedGlobal>0.2</WorkSpeedGlobal>
</statFactors>
</li>
</conditionalStatAffecters>
<exclusionTags>
<li>rjw_genes_hive_caste</li>
<li>rjw_genes_swearing_loyalty</li>
</exclusionTags>
<biostatCpx>7</biostatCpx>
<biostatMet>-3</biostatMet>
</GeneDef>
<GeneDef>
<defName>rjw_genes_drone</defName>
<label>Hive Drone</label>
<labelShortAdj>drone</labelShortAdj>
<description>This gene represents the drone caste amongst its xenotype. Drones are highly specialised experts that ensure the hives functioning. Other than that, drones are the only xenotypes capable of producing fertile offspring with a queen.</description>
<iconPath>Things/Mote/Heart</iconPath>
<displayOrderInCategory>2</displayOrderInCategory>
<displayCategory>rjw_genes_hive</displayCategory>
<exclusionTags>
<li>rjw_genes_hive_caste</li>
</exclusionTags>
<conditionalStatAffecters>
<li Class="RJW_Genes.ConditionalStatAffecter_QueenAbsent">
<statFactors>
<MoveSpeed>0.9</MoveSpeed>
</statFactors>
<statOffsets>
<WorkSpeedGlobal>-0.1</WorkSpeedGlobal>
</statOffsets>
</li>
</conditionalStatAffecters>
<biostatCpx>4</biostatCpx>
<biostatMet>-2</biostatMet>
</GeneDef>
<GeneDef>
<defName>rjw_genes_worker</defName>
<label>Hive Worker</label>
<labelShortAdj>worker</labelShortAdj>
<description>This gene represents the lowest caste of a hive, the workers. Usually sterile, they are despised by higher castes and only live to serve with labour.</description>
<iconPath>Things/Mote/Heart</iconPath>
<displayOrderInCategory>3</displayOrderInCategory>
<displayCategory>rjw_genes_hive</displayCategory>
<exclusionTags>
<li>rjw_genes_hive_caste</li>
</exclusionTags>
<conditionalStatAffecters>
<li Class="RJW_Genes.ConditionalStatAffecter_QueenAbsent">
<statFactors>
<MoveSpeed>0.7</MoveSpeed>
</statFactors>
<statOffsets>
<WorkSpeedGlobal>-0.5</WorkSpeedGlobal>
</statOffsets>
</li>
<li Class="RJW_Genes.ConditionalStatAffecter_MultipleQueens">
<statFactors>
<MoveSpeed>0.7</MoveSpeed>
</statFactors>
<statOffsets>
<WorkSpeedGlobal>-0.5</WorkSpeedGlobal>
</statOffsets>
</li>
<li Class="RJW_Genes.ConditionalStatAffecter_QueenCloseBy">
<statFactors>
<MoveSpeed>1.2</MoveSpeed>
<WorkSpeedGlobal>1.2</WorkSpeedGlobal>
</statFactors>
</li>
</conditionalStatAffecters>
<biostatCpx>1</biostatCpx>
<biostatMet>0</biostatMet>
</GeneDef>
<GeneDef>
<defName>rjw_genes_zealous_loyalty</defName>
<label>Zealous Loyalty</label>
<labelShortAdj>loyalty</labelShortAdj>
<description>Carriers of this gene are genetically wired to worship carriers of the 'Queen'-gene. They receive a massive relation-ship bonus towards the queen and a slight mood bonus. Having multiple queens in the colony causes severe distress.</description>
<iconPath>Things/Mote/Heart</iconPath>
<displayOrderInCategory>10</displayOrderInCategory>
<displayCategory>rjw_genes_hive</displayCategory>
<exclusionTags>
<li>rjw_genes_swearing_loyalty</li>
</exclusionTags>
<biostatCpx>1</biostatCpx>
<biostatMet>-1</biostatMet>
</GeneDef>
<GeneDef>
<defName>rjw_genes_cocoonweaver</defName>
@ -154,7 +25,7 @@
<labelShortAdj>cocooner</labelShortAdj>
<description>Carriers of this gene can generate tame spelopedes. Higher psychic-sensitivity will spawn more spelopedes.</description>
<iconPath>World/WorldObjects/Expanding/Insects</iconPath>
<displayOrderInCategory>12</displayOrderInCategory>
<displayOrderInCategory>11</displayOrderInCategory>
<displayCategory>rjw_genes_hive</displayCategory>
<abilities>
<li>rjw_genes_ability_spawn_spelopede</li>

View file

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<XenotypeDef>
<defName>rjw_genes_test_queen_xenotype</defName>
<label>Test Queen</label>
<iconPath>UI/Icons/Xenotypes/Sanguophage</iconPath>
<soundDefOnImplant>PawnBecameSanguophage</soundDefOnImplant>
<genes>
<li>rjw_genes_queen</li>
<li>rjw_genes_hypersexual</li>
<li>rjw_genes_female_only</li>
<li>Fertile</li>
<li>Skin_PaleYellow</li>
</genes>
</XenotypeDef>
<XenotypeDef>
<defName>rjw_genes_test_drone_xenotype</defName>
<label>Test Drone</label>
<iconPath>UI/Icons/Xenotypes/Sanguophage</iconPath>
<genes>
<li>rjw_genes_drone</li>
<li>rjw_genes_male_only</li>
<li>rjw_genes_zealous_loyalty</li>
<li>Fertile</li>
<li>Skin_DeepRed</li>
</genes>
</XenotypeDef>
</Defs>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Defs>
<RJW_Genes.QueenWorkerMappingDef>
<!-- Important: this default defName cannot be renamed! It is a protected keyword.-->
<!-- Changing the queenXenotype-Name will also throw an error.-->
<!-- But you can change the workerGenes list.-->
<defName>rjw_genes_default_worker_genes</defName>
<queenXenotype>default</queenXenotype>
<workerGenes>
<li>rjw_genes_worker</li>
<li>Sterile</li>
<li>rjw_genes_zealous_loyalty</li>
<li>Skin_Green</li>
</workerGenes>
</RJW_Genes.QueenWorkerMappingDef>
<RJW_Genes.QueenWorkerMappingDef>
<defName>rjw_genes_test_queen_worker_mapping</defName>
<queenXenotype>rjw_genes_test_queen_xenotype</queenXenotype>
<workerGenes>
<li>rjw_genes_worker</li>
<li>rjw_genes_zealous_loyalty</li>
<li>Skin_InkBlack</li>
</workerGenes>
</RJW_Genes.QueenWorkerMappingDef>
</Defs>

View file

@ -1,89 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<ThoughtDef>
<!-- For Challenged Queens -->
<defName>rjw_genes_rival_queen_mood</defName>
<workerClass>RJW_Genes.Thoughtworker_RivalQueen_Mood</workerClass>
<validWhileDespawned>false</validWhileDespawned>
<stages>
<li>
<label>Rivaled</label>
<description>There is another queen nearby!</description>
<baseMoodEffect>-70</baseMoodEffect>
</li>
</stages>
</ThoughtDef>
<ThoughtDef>
<!-- For Challenged Queens -->
<defName>rjw_genes_rival_queen_social</defName>
<thoughtClass>Thought_SituationalSocial</thoughtClass>
<workerClass>RJW_Genes.Thoughtworker_RivalQueen_Social</workerClass>
<stages>
<li>
<label>rivals me</label>
<description>{0} threatens my dominion. {0} must be perished.</description>
<baseOpinionOffset>-130</baseOpinionOffset>
</li>
</stages>
</ThoughtDef>
<ThoughtDef>
<!-- For Loyal Pawns -->
<defName>rjw_genes_multiple_queens_mood</defName>
<workerClass>RJW_Genes.Thoughtworker_MultipleQueens_Mood</workerClass>
<validWhileDespawned>false</validWhileDespawned>
<stages>
<li>
<label>Confused Servitude</label>
<description>I have too many queens around me!</description>
<baseMoodEffect>-30</baseMoodEffect>
</li>
</stages>
</ThoughtDef>
<ThoughtDef>
<!-- For Loyal Pawns -->
<defName>rjw_genes_queen_loyalty_social</defName>
<thoughtClass>Thought_SituationalSocial</thoughtClass>
<workerClass>RJW_Genes.Thoughtworker_QueenPresent_Social</workerClass>
<stages>
<li>
<label>Worship</label>
<description>{0} is my queen. My one and only reason to live.</description>
<baseOpinionOffset>+80</baseOpinionOffset>
</li>
</stages>
</ThoughtDef>
<ThoughtDef>
<!-- For Loyal Pawns -->
<defName>rjw_genes_no_queen_mood</defName>
<workerClass>RJW_Genes.Thoughtworker_QueenAbsent_Mood</workerClass>
<validWhileDespawned>false</validWhileDespawned>
<stages>
<li>
<label>Missing Queen</label>
<description>We do not have a queen! How are we suppossed to face the cruelties of the world without a shepherd?</description>
<baseMoodEffect>-20</baseMoodEffect>
</li>
</stages>
</ThoughtDef>
<ThoughtDef>
<!-- For Loyal Pawns -->
<defName>rjw_genes_queen_present_mood</defName>
<workerClass>RJW_Genes.Thoughtworker_QueenPresent_Mood</workerClass>
<validWhileDespawned>false</validWhileDespawned>
<stages>
<li>
<label>Queen Present</label>
<description>Our queen is so wonderful.</description>
<baseMoodEffect>+10</baseMoodEffect>
</li>
</stages>
</ThoughtDef>
</Defs>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<LanguageData>
<StatsReport_QueenCloseBy>queen in proximity</StatsReport_QueenCloseBy>
<StatsReport_QueenAbsent>queen absent</StatsReport_QueenAbsent>
<StatsReport_MultipleQueens>multiple queens present</StatsReport_MultipleQueens>
</LanguageData>

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using Verse;
namespace RJW_BGS
{
[StaticConstructorOnStartup]
internal static class HarmonyInit
{
// Token: 0x0600001F RID: 31 RVA: 0x000029A4 File Offset: 0x00000BA4
static HarmonyInit()
{
Harmony harmony = new Harmony("RJW_BGS");
harmony.PatchAll();
}
}
}

View file

@ -92,15 +92,6 @@ namespace RJW_Genes
public static readonly GeneDef rjw_genes_succubus_tail;
public static readonly GeneDef rjw_genes_succubus_wings;
// Hive
public static readonly GeneDef rjw_genes_queen;
public static readonly GeneDef rjw_genes_drone;
public static readonly GeneDef rjw_genes_worker;
public static readonly GeneDef rjw_genes_zealous_loyalty;
public static readonly GeneDef rjw_genes_cocoonweaver;
public static readonly GeneDef rjw_genes_spawn_spelopede;
//Other Defs
public static readonly XenotypeDef rjw_genes_succubus;
public static readonly DutyDef rjw_genes_flirt;

View file

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace RJW_Genes
{
/// <summary>
/// This def covers the birth of workers for each queen-xenotype.
///
/// It is used when a baby is born to a pawn with the queen-xenotype;
/// There is a random check for the type of the baby, and if the baby is born to be a worker,
/// additional genes are looked up here.
/// </summary>
public class QueenWorkerMappingDef : Def
{
public string queenXenotype;
public List<string> workerGenes;
}
}

View file

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace RJW_Genes
{
/// <summary>
/// Checks if there are multiple queens on the map.
/// </summary>
public class ConditionalStatAffecter_MultipleQueens : ConditionalStatAffecter
{
public override string Label => (string)"StatsReport_MultipleQueens".Translate();
public override bool Applies(StatRequest req)
{
if (req.Pawn == null || !req.Pawn.Spawned)
return false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
return false;
if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty))
{
return HiveUtility.QueensOnMap() >= 2;
}
return false;
}
}
}

View file

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace RJW_Genes
{
/// <summary>
/// Checks if there is no queen on the map.
/// </summary>
public class ConditionalStatAffecter_QueenAbsent : ConditionalStatAffecter
{
public override string Label => (string)"StatsReport_QueenAbsent".Translate();
public override bool Applies(StatRequest req)
{
if (req.Pawn == null || !req.Pawn.Spawned)
return false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
return false;
if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty))
{
return HiveUtility.QueensOnMap() == 0;
}
return false;
}
}
}

View file

@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace RJW_Genes
{
/// <summary>
/// Checks if there is (exactly) one queen nearby.
/// If the pawn is a queen itself, it's checked if there are OTHER queens nearby.
/// While this is used for mostly positive things for workers and drones, for queens it checks if there is a rival nearby.
/// </summary>
public class ConditionalStatAffecter_QueenCloseBy : ConditionalStatAffecter
{
const float EFFECT_DISTANCE = 10.0f;
public override string Label => (string)"StatsReport_QueenCloseBy".Translate();
public override bool Applies(StatRequest req)
{
if (req.Pawn == null || !req.Pawn.Spawned)
return false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(req.Pawn))
return false;
// Case A: Check for Loyal Pawns if their One Queen is nearby
if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
{
Pawn queen = HiveUtility.GetQueensOnMap()[0];
return req.Pawn.Position.DistanceTo(queen.Position) <= EFFECT_DISTANCE;
}
// Case A: Check for Queen if another Queen is nearby
if (GeneUtility.HasGeneNullCheck(req.Pawn, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() >= 2)
{
foreach (Pawn queen in HiveUtility.GetQueensOnMap())
{
if (queen != req.Pawn && req.Pawn.Position.DistanceTo(queen.Position) <= EFFECT_DISTANCE)
return true;
}
}
return false;
}
}
}

View file

@ -1,208 +0,0 @@
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace RJW_Genes
{
internal class HiveUtility
{
/// <summary>
/// Checks for existance of the RJW-Gene `queen`, if the pawn is spawned and if the pawn has reached adulthood.
/// Despite the naming, a Queen can also be male.
/// </summary>
/// <param name="pawn">The pawn that could be an Adult Queen</param>
/// <returns>Whether the pawn is an adult queen.</returns>
public static bool IsAdultQueen(Pawn pawn)
{
if (pawn == null || !pawn.Spawned)
return false;
if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_queen))
{
return pawn.ageTracker.Adult;
}
return false;
}
public static int QueensOnMap() => GetQueensOnMap().Count;
/// <summary>
/// Checks for all pawns on the Players Home Map if they are an adult queen.
/// Adultness is determined by Base-Game Logic, Queen is determined by the rjw_genes_queen GeneDefOf (Not Xenotype).
/// </summary>
/// <returns>A list of queens on the players HomeMap</returns>
public static List<Pawn> GetQueensOnMap()
{
Map map = Find.Maps.Where(mapCandidate => mapCandidate.IsPlayerHome).First();
if (map != null)
{
List<Pawn> playersPawns = map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer);
return playersPawns.FindAll(pawn => pawn.Spawned && IsAdultQueen(pawn));
}
// Fallback: Something is wrong with Map
return new List<Pawn>();
}
/// <summary>
/// Checks if the pawn is on the players home map.
///
/// Reason is that drones should only be punished for absence of queen if they are on the map and there is no queen.
/// If they are on a mission, transport-pod etc. they should not get boni or mali.
/// </summary>
/// <param name="pawn">The pawn for which to check map-presence.</param>
/// <returns>True if the pawn is on the home-map, False otherwise.</returns>
public static bool PawnIsOnHomeMap(Pawn pawn)
{
Map homeMap = Find.Maps.Where(mapCandidate => mapCandidate.IsPlayerHome).First();
return
homeMap != null && pawn != null
&& pawn.Spawned
&& pawn.Map == homeMap;
}
/// <summary>
/// Returns the Xenotype of a pawn if the pawn has a xenotype with the queen gene.
/// Null otherwise.
/// </summary>
/// <param name="pawn"></param>
/// <returns>A xenotype with a queen gene, or null.</returns>
public static XenotypeDef TryGetQueenXenotype(Pawn pawn)
{
if (pawn == null)
return null;
if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_queen))
{
var potentialXenotype = pawn.genes.Xenotype;
if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_queen))
{
return potentialXenotype;
}
}
return null;
}
/// <summary>
/// Returns the Xenotype of a pawn if the pawn has a xenotype with the drone gene.
/// Null otherwise.
/// </summary>
/// <param name="pawn"></param>
/// <returns>A xenotype with a drone gene, or null.</returns>
public static XenotypeDef TryGetDroneXenotype(Pawn pawn)
{
if (pawn == null)
return null;
if (GeneUtility.HasGeneNullCheck(pawn, GeneDefOf.rjw_genes_drone))
{
var potentialXenotype = pawn.genes.Xenotype;
if (potentialXenotype != null && potentialXenotype.genes.Contains(GeneDefOf.rjw_genes_drone))
{
return potentialXenotype;
}
}
return null;
}
/// <summary>
/// Looks up the Queen-WorkerMappings and returns a cleaned / updated dictionary.
///
/// This method takes care of genes maybe not existing (from other mods) or misspellings etc.
/// Prints a bigger piece of information when debug printing is enabled.
/// </summary>
/// <returns>A mapping which Queen-Xenotypes should produce which worker genes.</returns>
public static Dictionary<XenotypeDef,List<GeneDef>> GetQueenWorkerMappings()
{
Dictionary<XenotypeDef,List<GeneDef>> dict = new Dictionary<XenotypeDef, List<GeneDef>>();
IEnumerable<QueenWorkerMappingDef> mappingDefs = DefDatabase<QueenWorkerMappingDef>.AllDefs;
if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"Found {mappingDefs.Count()} Queen-Worker mappings in defs");
// Dev-Note: I first a nice lambda here, but I used nesting in favour of logging.
foreach (QueenWorkerMappingDef mappingDef in mappingDefs)
{
if (mappingDef.defName == "rjw_genes_default_worker_genes")
{
// Do nothing, there is no lookup but this entry is fine and should not log a warning.
continue;
}
XenotypeDef queenDef = DefDatabase<XenotypeDef>.GetNamed(mappingDef.queenXenotype);
if (queenDef != null)
{
List<GeneDef> workerGenes = new List<GeneDef>();
foreach (string geneName in mappingDef.workerGenes)
{
GeneDef workerGene = DefDatabase<GeneDef>.GetNamed(geneName);
if (workerGene != null)
workerGenes.Add(workerGene);
else if(RJW_Genes_Settings.rjw_genes_detailed_debug)
ModLog.Warning($"Could not look up Gene {geneName} for {mappingDef.queenXenotype}.");
}
dict.Add(queenDef, workerGenes);
}
else {
if (RJW_Genes_Settings.rjw_genes_detailed_debug)
ModLog.Warning($"Did not find a matching xenotype for {mappingDef.queenXenotype}! Defaulting to rjw_genes_default_worker_genes.");
}
}
return dict;
}
/// <summary>
/// Looks up the default genes for any queen offspring that has no other definition for it.
/// This is done by looking for the mapping with *exactly* defName rjw_genes_default_worker_genes.
///
/// The idea is that players can edit the default types, but that this is a protected keyword.
/// </summary>
/// <returns>A list of genes for workers that do not have specific mappings defined.</returns>
public static List<GeneDef> LookupDefaultWorkerGenes()
{
IEnumerable<QueenWorkerMappingDef> mappingDefs = DefDatabase<QueenWorkerMappingDef>.AllDefs;
List<GeneDef> workerGenes = new List<GeneDef>();
var defaultMapping = mappingDefs.First(m => m.defName == "rjw_genes_default_worker_genes");
if (defaultMapping == null)
{
ModLog.Error("Did not find default worker genes for queen-offspring! Please make sure you did not rename the 'rjw_genes_default_worker_genes'.");
return workerGenes;
}
foreach (string geneName in defaultMapping.workerGenes)
{
GeneDef workerGene = DefDatabase<GeneDef>.GetNamed(geneName);
if (workerGene != null)
workerGenes.Add(workerGene);
else if (RJW_Genes_Settings.rjw_genes_detailed_debug)
ModLog.Warning($"Could not look up gene {geneName} for rjw_genes_default_worker_genes.");
}
return workerGenes;
}
public static IEnumerable<XenotypeDef> getQueenXenotypes()
{
return DefDatabase<XenotypeDef>.AllDefs.Where(type => type.genes.Contains(GeneDefOf.rjw_genes_queen));
}
public static IEnumerable<XenotypeDef> getDroneXenotypes()
{
return DefDatabase<XenotypeDef>.AllDefs.Where(type => type.genes.Contains(GeneDefOf.rjw_genes_drone));
}
}
}

View file

@ -1,150 +0,0 @@
using HarmonyLib;
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace RJW_Genes
{
/// <summary>
/// Patches the method `ApplyBirthOutcome` from `PregnancyUtility`.
///
/// The 'ApplyBirthOutcome' returns the finished baby, for which we alter the pawn according to our xenotypes.
/// </summary>
[HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))]
public class Patch_BirthOutcome_SetHiveGenes
{
const double QUEEN_CHANCE = 0.01f;
const double DRONE_CHANCE = 0.49f;
const double WORKER_CHANCE = 1 - QUEEN_CHANCE - DRONE_CHANCE;
[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.");
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;
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);
// 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 < QUEEN_CHANCE)
{
pawn.genes.SetXenotype(queenDef);
if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a new queen with xenotype {queenDef.defName} ({QUEEN_CHANCE*100}% chance,rolled {roll})");
// TODO: Make a letter ?
}
// Case 2.b: New Drone born
else if (roll < DRONE_CHANCE + QUEEN_CHANCE)
{
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} ({(DRONE_CHANCE + QUEEN_CHANCE) * 100}% chance,rolled {roll}))");
}
// Case 2.c: Worker
else {
if (RJW_Genes_Settings.rjw_genes_detailed_debug) ModLog.Message($"{pawn} born as a worker ({(WORKER_CHANCE) * 100}% chance,rolled {roll}))");
MakeWorker(pawn, queenDef);
}
}
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="pawnTobeWorker">The pawn for which the genes are added.</param>
/// <param name="queenDef">The xenotype of the queen, used for lookup.</param>
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);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="pawn">The pawn for whichs parent the xenotypes is looked up.</param>
/// <returns>The Drone-Xenotype of a parent or null. If both are drones, mothers are preferred.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="pawn">The pawn for whichs parent the xenotypes is looked up.</param>
/// <returns>The Queen-Xenotype of a parent or null. If both are queens, mothers are preferred.</returns>
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;
}
}
}

View file

@ -1,40 +0,0 @@
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 ThoughtWorker_QueenPresent_Social : ThoughtWorker
{
protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn other)
{
if (!p.RaceProps.Humanlike)
return (ThoughtState) false;
if (!other.RaceProps.Humanlike)
return (ThoughtState) false;
if (!RelationsUtility.PawnsKnowEachOther(p, other))
return (ThoughtState) false;
// Only check if they are spawned
if (!p.Spawned || !other.Spawned)
return (ThoughtState)false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
{
return (ThoughtState) HiveUtility.IsAdultQueen(other);
}
return (ThoughtState)false;
}
}
}

View file

@ -1,39 +0,0 @@
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 ThoughtWorker_RivalQueen_Social : ThoughtWorker
{
protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn other)
{
if (!p.RaceProps.Humanlike)
return (ThoughtState)false;
if (!other.RaceProps.Humanlike)
return (ThoughtState)false;
if (!RelationsUtility.PawnsKnowEachOther(p, other))
return (ThoughtState)false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
// Only check if they are spawned
if (!p.Spawned || !other.Spawned)
{
return (ThoughtState)false;
}
if(HiveUtility.IsAdultQueen(p) && HiveUtility.IsAdultQueen(other))
{
return (ThoughtState)true;
}
return (ThoughtState)false;
}
}
}

View file

@ -1,36 +0,0 @@
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 Thoughtworker_MultipleQueens_Mood : ThoughtWorker
{
protected override ThoughtState CurrentStateInternal(Pawn p)
{
// Error Handling and Check for Pawn being on Map
if (p == null || !p.Spawned)
return (ThoughtState) false;
// Queens cannot have loyalty thoughts
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
return (ThoughtState)false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() >= 2)
{
return (ThoughtState)true;
}
return (ThoughtState) false;
}
}
}

View file

@ -1,36 +0,0 @@
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 Thoughtworker_QueenAbsent_Mood : ThoughtWorker
{
protected override ThoughtState CurrentStateInternal(Pawn p)
{
// Error Handling and Check for Pawn being on Map
if (p == null || !p.Spawned)
return (ThoughtState) false;
// Queens cannot have loyalty thoughts
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
return (ThoughtState)false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 0)
{
return (ThoughtState)true;
}
return (ThoughtState) false;
}
}
}

View file

@ -1,36 +0,0 @@
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 Thoughtworker_QueenPresent_Mood : ThoughtWorker
{
protected override ThoughtState CurrentStateInternal(Pawn p)
{
// Error Handling and Check for Pawn being on Map
if (p == null || !p.Spawned)
return (ThoughtState) false;
// Queens cannot have loyalty thoughts
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_queen))
return (ThoughtState)false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
if (GeneUtility.HasGeneNullCheck(p, GeneDefOf.rjw_genes_zealous_loyalty) && HiveUtility.QueensOnMap() == 1)
{
return (ThoughtState)true;
}
return (ThoughtState) false;
}
}
}

View file

@ -1,32 +0,0 @@
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 Thoughtworker_RivalQueen_Mood : ThoughtWorker
{
protected override ThoughtState CurrentStateInternal(Pawn p)
{
if (p == null || !p.Spawned)
return (ThoughtState) false;
// If the pawn is not on Map (e.g. caravan), no mali
if (!HiveUtility.PawnIsOnHomeMap(p))
return (ThoughtState)false;
if (HiveUtility.IsAdultQueen(p) && HiveUtility.QueensOnMap() >= 2)
{
return (ThoughtState) true;
}
return (ThoughtState) false;
}
}
}

View file

@ -1,20 +1,10 @@
using System.Linq;
using Verse;
using Verse;
namespace RJW_Genes
namespace BTE_MMLA
{
[StaticConstructorOnStartup]
public static class RJW_Genes
{
static RJW_Genes()
{
ModLog.Message("RJW-Genes loaded");
if (RJW_Genes_Settings.rjw_genes_detailed_debug)
{
ModLog.Message($"{HiveUtility.getQueenXenotypes().EnumerableCount()} Queen-Xenotypes ({string.Join(",", HiveUtility.getQueenXenotypes().Select(t => t.defName))})");
ModLog.Message($"{HiveUtility.getDroneXenotypes().EnumerableCount()} Drone-Xenotypes ({string.Join(",", HiveUtility.getDroneXenotypes().Select(t => t.defName))})");
ModLog.Message($"Found {HiveUtility.GetQueenWorkerMappings().Count} Queen-Worker Mappings ({string.Join(",", HiveUtility.GetQueenWorkerMappings().Keys.Select(t => t.defName))} + Default) ");
}
}
static RJW_Genes() => Log.Message("RJW-Genes loaded");
}
}

View file

@ -30,6 +30,7 @@
<None Include="..\Common\Patches\**" />
</ItemGroup>
<ItemGroup>
<Compile Include="Animal_Inheritance\Harmony_Init.cs" />
<Compile Include="Animal_Inheritance\InheritanceUtility.cs" />
<Compile Include="Animal_Inheritance\Patches\Patch_RJW_BestialityPregnancyUtility.cs" />
<Compile Include="Animal_Inheritance\Patches\Patch_RJW_HediffInsect_Egg.cs" />
@ -90,18 +91,6 @@
<Compile Include="Genes\Hive\Abilities\CompAbilityEffect_CocoonWeaver.cs" />
<Compile Include="Genes\Hive\Abilities\CompProperties_AbilitySpawnSpelopede.cs" />
<Compile Include="Genes\Hive\Abilities\CompProperties_AbilityCocoonWeaver.cs" />
<Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_MultipleQueens.cs" />
<Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_QueenCloseBy.cs" />
<Compile Include="Genes\Hive\Genes\ConditionalStatAffecters\ConditionalStatAffecter_QueenAbsent.cs" />
<Compile Include="Genes\Hive\Helpers\HiveUtility.cs" />
<Compile Include="Genes\Hive\Defs\QueenWorkerMappingDef.cs" />
<Compile Include="Genes\Hive\Patches\Patch_BirthOutcome_SetHiveGenes.cs" />
<Compile Include="Genes\Hive\Thoughts\Thoughtworker_QueenAbsent_Mood.cs" />
<Compile Include="Genes\Hive\Thoughts\Thoughtworker_MultipleQueens_Mood.cs" />
<Compile Include="Genes\Hive\Thoughts\Thoughtworker_QueenPresent_Mood.cs" />
<Compile Include="Genes\Hive\Thoughts\Thoughtworker_RivalQueen_Mood.cs" />
<Compile Include="Genes\Hive\Thoughts\ThoughtWorker_QueenPresent_Social.cs" />
<Compile Include="Genes\Hive\Thoughts\ThoughtWorker_RivalQueen_Social.cs" />
<Compile Include="Genes\Life_Force\Abilities\AbilityUtility.cs" />
<Compile Include="Genes\Life_Force\UI\Alert_LowFertilin.cs" />
<Compile Include="Genes\Life_Force\Abilities\CompAbilityEffect_CasterIsNaked.cs" />
@ -207,6 +196,5 @@
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>