2023-06-04 07:36:51 +00:00
using RimWorld ;
using System ;
2023-06-04 08:09:51 +00:00
using System.Collections ;
2023-06-04 07:36:51 +00:00
using System.Collections.Generic ;
using System.Linq ;
2023-06-04 08:09:51 +00:00
using System.Reflection.Emit ;
2023-06-04 07:36:51 +00:00
using System.Text ;
using System.Threading.Tasks ;
using Verse ;
namespace RJW_Genes
{
2023-06-04 08:34:59 +00:00
/// <summary>
/// DevNote: Issue #37 came along because I checked for getMother() and getFather(), but it can happen that a pawn has two mothers.
/// They are called Mother if they have a ParentRelation and are female.
/// New behaviour iterates over all parents and returns the first queen/drone or null.
/// </summary>
2023-06-04 07:36:51 +00:00
public class HiveBirthLogic
{
/// <summary>
/// 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
/// </summary>
/// <param name="pawn">The pawn born, that maybe becomes a hive-xenotype.</param>
/// <param name="hasDroneParent">whether there was a drone parent involved</param>
2023-06-05 14:52:55 +00:00
public static void ManageHiveBirth ( Pawn pawn , bool hasDroneParent = false , XenotypeDef fallbackQueenDef = null , XenotypeDef fallbackDroneDef = null )
2023-06-04 07:36:51 +00:00
{
XenotypeDef queenDef = TryFindParentQueenXenotype ( pawn ) ;
2023-06-05 14:52:55 +00:00
if ( queenDef = = null ) queenDef = fallbackQueenDef ;
2023-06-04 07:36:51 +00:00
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})" ) ;
2023-06-04 15:03:11 +00:00
MakeQueenBornLetter ( pawn ) ;
2023-06-04 07:36:51 +00:00
}
// Case 2.b: New Drone born
else if ( roll < hiveOffspringChanceDef . droneChance + hiveOffspringChanceDef . queenChance )
{
XenotypeDef droneDef = TryFindParentDroneXenotype ( pawn ) ;
2023-06-05 14:52:55 +00:00
if ( droneDef = = null ) droneDef = fallbackDroneDef ;
2023-06-04 07:36:51 +00:00
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 ) ;
}
}
}
/// <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 ) ;
2023-06-04 08:09:51 +00:00
pawnTobeWorker . genes . xenotypeName = "Worker" ;
2023-06-04 07:36:51 +00:00
}
/// <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>
public static XenotypeDef TryFindParentDroneXenotype ( Pawn pawn )
{
if ( pawn = = null )
return null ;
2023-06-04 08:34:59 +00:00
List < DirectPawnRelation > parentRelations = pawn . relations . DirectRelations . FindAll ( rel = > rel . def . Equals ( PawnRelationDefOf . Parent ) ) ;
foreach ( DirectPawnRelation parent in parentRelations )
{
XenotypeDef xenotype = HiveUtility . TryGetDroneXenotype ( parent . otherPawn ) ;
if ( xenotype ! = null ) return xenotype ;
}
2023-06-04 07:36:51 +00:00
return null ;
}
2023-06-04 15:03:11 +00:00
public static void MakeQueenBornLetter ( Pawn bornQueen )
{
if ( bornQueen = = null ) return ;
var letter = LetterMaker . MakeLetter (
"New Queen" , "A new Queen was born! Make sure to adress inheritance before the new queen reaches adolesence." , LetterDefOf . NeutralEvent , bornQueen
) ;
//letter.Start();
Find . LetterStack . ReceiveLetter ( letter ) ;
}
2023-06-04 07:36:51 +00:00
/// <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).
2023-06-04 08:34:59 +00:00
/// If both are queens, the first is returned.
2023-06-04 07:36:51 +00:00
/// </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>
public static XenotypeDef TryFindParentQueenXenotype ( Pawn pawn )
{
if ( pawn = = null )
return null ;
2023-06-04 08:34:59 +00:00
List < DirectPawnRelation > parentRelations = pawn . relations . DirectRelations . FindAll ( rel = > rel . def . Equals ( PawnRelationDefOf . Parent ) ) ;
foreach ( var parent in parentRelations )
{
XenotypeDef xenotype = HiveUtility . TryGetQueenXenotype ( parent . otherPawn ) ;
if ( xenotype ! = null ) return xenotype ;
}
2023-06-04 07:36:51 +00:00
return null ;
}
}
}