import source

This commit is contained in:
Izaya 2023-01-15 10:55:51 +11:00
parent 5e4965be74
commit 4b541f6625
17 changed files with 559 additions and 0 deletions

1
.gitignore vendored
View File

@ -259,3 +259,4 @@ __pycache__/
/1.4/Assemblies/HarmonyMod.dll
/1.4/Assemblies/0MultiplayerAPI.dll
/1.4/Assemblies/0Harmony.dll
/1.4/Assemblies/LitterBiotech.dll

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<GeneDef>
<defName>LitteredBirths</defName>
<label>littered births</label>
<description>Female carriers of this gene birth litters instead of just one baby, with a chance of having two to four babies per pregnancy.</description>
<iconPath>Icons/Genes/Gene_LitteredBirths</iconPath>
<!-- <geneClass>Gene_Clotting</geneClass> -->
<displayOrderInCategory>110</displayOrderInCategory>
<marketValueFactor>1.25</marketValueFactor>
<biostatMet>0</biostatMet>
<biostatCpx>1</biostatCpx>
</GeneDef>
</Defs>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<LetterDef Name="AnotherBaby">
<defName>AnotherBaby</defName>
<color>(120, 176, 216)</color>
<flashColor>(106, 179, 231)</flashColor>
<flashInterval>40</flashInterval>
<arriveSound>LetterArrive_Good</arriveSound>
<pauseMode>MajorThreat</pauseMode>
</LetterDef>
</Defs>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<LBTSettings>Litter Biotech</LBTSettings>
<EnableLBTDevLogging>Enable development logging</EnableLBTDevLogging>
<EnableLBTDevLoggingDesc>When enabled, this setting provides additional Litter Biotech related logging in the development mode log.</EnableLBTDevLoggingDesc>
<RegretStealingLovinThoughtDisabled>Disable "Regrets stealing lovin'" thought</RegretStealingLovinThoughtDisabled>
<RegretStealingLovinThoughtDisabledDesc>By default, the limbic stimulator implant allows for pawns without the Rapist trait to steal lovin'. When this occurs, the non-rapist pawn will receive a -5 mood negative thought that stacks up to 3 times. When enabled, this setting disables generation of that thought.</RegretStealingLovinThoughtDisabledDesc>
</LanguageData>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
About/About.xml Normal file
View File

@ -0,0 +1,25 @@
<ModMetaData>
<name>Litters for Biotech</name>
<author>leboeuf</author>
<packageId>leboeuf.litters</packageId>
<supportedVersions>
<li>1.4</li>
</supportedVersions>
<incompatibleWith />
<loadAfter>
<li>rim.job.world</li>
</loadAfter>
<description>
Litter Biotech is a small RimWorld: Biotech expansion for RimJobWorld.
Features:
• Biotech pregnancy compatible multibirth system, allowing
pawns to have random twins with a default 1-in-100 chance.
• Littered births gene, where pawns can have guaranteed
litters of multiple babies.
For all feature requests and bugs/issues:
https://gitgud.io/leboeuf/litter-biotech/-/issues
</description>
</ModMetaData>

22
LitterBiotech.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LitterBiotech", "Source\LitterBiotech.csproj", "{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {28CF9A73-5333-4EB3-BFCC-3FBEDDA19200}
EndGlobalSection
EndGlobal

11
Source/DefOf/GeneDefOf.cs Normal file
View File

@ -0,0 +1,11 @@
using RimWorld;
using Verse;
namespace LitterBiotech
{
[RimWorld.DefOf]
public static class GeneDefOf
{
public static GeneDef LitteredBirths;
}
}

View File

@ -0,0 +1,14 @@
using RimWorld;
using Verse;
namespace LitterBiotech
{
[RimWorld.DefOf]
public static class HediffDefOf
{
// public static HediffDef Infatuo;
// public static HediffDef InfatuoCalibrating;
public static HediffDef OvaryAgitator;
public static HediffDef Bioscaffold;
}
}

View File

@ -0,0 +1,11 @@
using RimWorld;
using Verse;
namespace LitterBiotech
{
[RimWorld.DefOf]
public static class LetterDefOf
{
public static LetterDef AnotherBaby;
}
}

57
Source/Hediffs/Infatuo.cs Normal file
View File

@ -0,0 +1,57 @@
// FOR ANYONE (THAT ISN"T ME (BOEUF)) THAT CARES
// =====================
// This is an idea for an implant that I had that basically forces a pawn to romantically obsess about another pawn, but I'm taking a break from working on it
// because I'm too smoothbrain to work out relation defs and making custom relations, and the multibirth stuff was taking up my time as is
// If you want to mess with it, this code is here for shits and gigs - modify it, throw it out, make something new, idgaf
/*using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LitterBiotech.Hediffs
{
class Infatuo
{
public class PawnRelationWorker_InfatuoInfatuated : PawnRelationWorker
{
// BaseGenerationChanceFactor - should NEVER autogenerate on pawns (for now, anyway)
new public float BaseGenerationChanceFactor(Pawn generated, Pawn other, PawnGenerationRequest request)
{
return 0.0f;
}
// CreateRelation - shouldn't be needed for now since we're not autogenerating infatuo relations, but may be used in future
public override void CreateRelation(Pawn generated, Pawn other, ref PawnGenerationRequest request)
{
return;
}
// GenerationChance - should NEVER autogenerate on pawns (for now, anyway)
public override float GenerationChance(Pawn generated, Pawn other, PawnGenerationRequest request)
{
return 0.0f;
}
public override bool InRelation(Pawn me, Pawn other)
{
return (me.health.hediffSet.GetFirstHediff<Hediff_Infatuo>().target == other);
}
}
public class Hediff_Infatuo : Hediff
{
public Hediff_Infatuo(Pawn intTarget)
{
target = intTarget;
}
public Pawn target;
}
public class Hediff_InfatuoCalibrating : Hediff
{
}
}
}*/

View File

@ -0,0 +1,35 @@
using Verse;
namespace LitterBiotech.Helpers
{
public static class LBTLogger
{
public static void Message(string message)
{
Log.Message("[INFO][LitterBT] - " + message);
}
public static void Warning(string message)
{
Log.Message("[WARN][LitterBT] - " + message);
}
public static void Error(string message)
{
Log.Message("[ ERR][LitterBT] - " + message);
}
public static void MessageGroupHead(string message)
{
Log.Message("[INFO][LitterBT]╦═ " + message);
}
public static void MessageGroupBody(string message)
{
Log.Message("[INFO][LitterBT]╠═══ " + message);
}
public static void MessageGroupFoot(string message)
{
Log.Message("[INFO][LitterBT]╚═══ " + message);
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using RimWorld;
using Verse;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LitterBiotech
{
class LaborState
{
public Pawn pawn;
public int birthTotal = 0;
public int birthCount = 1;
public bool hasOvaryAgitator = false;
public bool hasBioscaffold = false;
public LaborState(Pawn pawn, int birthTotal)
{
this.pawn = pawn;
this.birthTotal = birthTotal;
this.birthCount = 0;
this.hasOvaryAgitator = pawn.health.hediffSet.HasHediff(HediffDef.Named("OvaryAgitator"));
this.hasBioscaffold = pawn.health.hediffSet.HasHediff(HediffDef.Named("OvaryAgitator"));
}
}
}

161
Source/LitterBiotech.cs Normal file
View File

@ -0,0 +1,161 @@
using HarmonyLib;
using RimWorld;
using LitterBiotech.Helpers;
using System.Collections.Generic;
using Verse;
namespace LitterBiotech
{
[StaticConstructorOnStartup]
public class LitterBiotechMod
{
static Dictionary<string, LaborState> laborStateMap = new Dictionary<string, LaborState>();
static LitterBiotechMod()
{
Harmony harmony = new Harmony(id: "rimworld.leboeuf.litterbiotech");
// Hediff_Labor state capture
harmony.Patch(AccessTools.Method(typeof(Hediff_Labor), nameof(Hediff_Labor.PostRemoved)),
postfix: new HarmonyMethod(typeof(LitterBiotechMod), nameof(Hediff_Labor_PostRemovedPostFix)));
// Gene_LitteredBirths multibirth logic
harmony.Patch(AccessTools.Method(typeof(Hediff_LaborPushing), nameof(Hediff_LaborPushing.PostRemoved)),
postfix: new HarmonyMethod(typeof(LitterBiotechMod), nameof(Hediff_LaborPushing_PostRemovedPostFix)));
LBTLogger.Message("Litter Biotech started successfully.");
if (LBTSettings.devMode)
{
LBTLogger.Message("Notice: Developer logging for Litter Biotech is currently active - it can be disabled in the mod settings.");
}
}
// Notes about Hediff_Labor_PostRemovedPostFix
// ===========================================
// Alright, didn't really want to make a patch for Labor as well as LaborPushing, but I have to because otherwise there's
// no way to assign a doctor on second/third/etc births if I only use LaborPushing, which can disproportionately cause
// more stillbirths than you might normally have
//
// I TRIED to modify the ChildBirth lord job and ritual code to allow the first doctor that was assigned and any childbirth
// attendees to just autoreassign themselves to the next births, but it wasn't working - for now, I'm not happy with how I'm
// doing this because multiple births now require:
// 1. (potentially several) forced pauses with letters telling the player to reassign a doctor to the mother who's giving birth to another child
// 2. A LOT of state carrying (that I likely overengineered :v) ) between hediff removes and adds
//
// I've got a dictionary now for storing state across hediffs and on multiple pawns, instead of what I was originally doing, which was using
// severity as a way of tracking state. LaborState class should help keep things a little more organized.
//
// I'll revisit this in the future (probably). Thanks for coming to my TED talk
static void Hediff_Labor_PostRemovedPostFix(ref Hediff_Labor __instance)
{
bool randomTwinsRoll;
int totalBirths;
bool laborStateIsNull = !laborStateMap.ContainsKey(__instance.pawn.ThingID);
bool hasLitteredBirthsGene = __instance.pawn.genes.HasGene(LitterBiotech.GeneDefOf.LitteredBirths);
// we'll never do additional processing if this is the guaranteed last birth (eg birth #4)
if (!laborStateIsNull && laborStateMap.TryGetValue(__instance.pawn.ThingID).birthCount == 4)
{
return;
}
// For now, littered birth overrides twin calculations, so if a LaborState already exists
// with littered births gene, move on
if (!laborStateIsNull && hasLitteredBirthsGene)
{
if (LBTSettings.devMode)
{
LBTLogger.MessageGroupHead("Found active LaborState and LitteredBirths gene - skipping additional Hediff_Labor_PostRemovedPostFix work");
LBTLogger.MessageGroupBody("Pawn: " + __instance.pawn.NameShortColored + " (" + __instance.pawn.ThingID + ")");
LBTLogger.MessageGroupFoot("birthCount: " + laborStateMap.TryGetValue(__instance.pawn.ThingID).birthCount);
}
return;
}
// Make a new LaborState for the null case with littered births
if (laborStateIsNull && hasLitteredBirthsGene)
{
LBTLogger.Message("Found littered births gene");
int litteredBirthsTotalRoll = Rand.RangeInclusive(2, 4);
laborStateMap.SetOrAdd(__instance.pawn.ThingID, new LaborState(__instance.pawn, litteredBirthsTotalRoll));
return;
}
// Finally, regardless of littered births gene, we only want new state creation on
// pawns that don't already have state, so return if state is !null (STATE SHOULD ALWAYS BE CLEANED IN LABORPUSHING POSTFIX)
if (!laborStateIsNull)
{
if (LBTSettings.devMode)
{
LBTLogger.Warning("Labor state for pawn " + __instance.pawn.NameShortColored + " (" + __instance.pawn.ThingID + ") is not null despite all checks passing for determining first instance of Hediff_Labor - this warning should never occur, and may indicate a bug in Hediff_LaborPushing of lingering labor state from a previous pregnancy");
}
return;
}
// For everything else, we do random twin handling
// -------
// If we fail a base chance twins roll, return without any additional processing and proceed with vanilla childbirth
// Notes on rolls:
// -> Chance with Littered Births gene: random between 2 and 4 (inclusive)
randomTwinsRoll = Rand.Chance(0.01f);
if (!randomTwinsRoll)
{
// We failed rolls - no additional processing, do vanilla single baby birth
if (LBTSettings.devMode)
{
LBTLogger.MessageGroupHead("Inside Hediff_Labor_PostRemovedPostFix random twins check fail");
LBTLogger.MessageGroupBody("Pawn: " + __instance.pawn.NameShortColored);
LBTLogger.MessageGroupBody("Random twins roll outcome: " + randomTwinsRoll);
}
return;
}
totalBirths = 2;
bool doTriplets = Rand.Chance(0.5f);
bool doQuadruplets = Rand.Chance(0.1f);
if (doTriplets) totalBirths = 3;
if (doTriplets && doQuadruplets) totalBirths = 4;
// Set new LaborState
laborStateMap.Add(__instance.pawn.ThingID, new LaborState(__instance.pawn, totalBirths));
}
static void Hediff_LaborPushing_PostRemovedPostFix(ref Hediff_LaborPushing __instance)
{
bool hasLitteredBirthsGene = __instance.pawn.genes.HasGene(LitterBiotech.GeneDefOf.LitteredBirths);
bool laborStateIsNull = !laborStateMap.ContainsKey(__instance.pawn.ThingID);
LaborState currentLaborState;
laborStateMap.TryGetValue(__instance.pawn.ThingID, out currentLaborState);
if (laborStateIsNull)
{
return;
}
if (currentLaborState.birthTotal == currentLaborState.birthCount)
{
laborStateMap.Remove(__instance.pawn.ThingID);
if (__instance.pawn.health.hediffSet.HasHediff(HediffDef.Named("Bioscaffold"))) {
__instance.pawn.health.RemoveHediff(__instance.pawn.health.hediffSet.GetFirstHediffOfDef(LitterBiotech.HediffDefOf.Bioscaffold));
}
return;
}
((Hediff_Labor)__instance.pawn.health.AddHediff(RimWorld.HediffDefOf.PregnancyLabor)).SetParents(__instance.pawn, __instance.Father, PregnancyUtility.GetInheritedGeneSet(__instance.Father, __instance.pawn));
currentLaborState.birthCount++;
if (!hasLitteredBirthsGene)
{
if (LBTSettings.devMode)
{
LBTLogger.Message("Pawn " + __instance.pawn.NameShortColored + " (" + __instance.pawn.ThingID + ") is having random twins");
}
Find.LetterStack.ReceiveLetter("Twins!", __instance.pawn.NameShortColored + " is still in labor and is having twins!\n\nBe sure to gather your doctor and additional friends and family to ensure the other baby is also born healthy!", LitterBiotech.LetterDefOf.AnotherBaby, __instance.pawn);
return;
}
Find.LetterStack.ReceiveLetter("Another baby!", __instance.pawn.NameShortColored + " is still in labor and is having another baby!\n\nBe sure to gather your doctor and additional friends and family to ensure the next baby is also born healthy!", LitterBiotech.LetterDefOf.AnotherBaby, __instance.pawn);
}
}
}

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D7D21B4A-1DA7-41D8-B202-C58CA8FA62AA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LitterBiotech</RootNamespace>
<AssemblyName>LitterBiotech</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\1.4\Assemblies\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\..\..\..\..\workshop\content\294100\2009463077\Current\Assemblies\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>..\..\..\RimWorldLinux_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="HarmonyMod">
<HintPath>..\..\..\..\..\workshop\content\294100\2009463077\Current\Assemblies\HarmonyMod.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="UnityEngine">
<HintPath>..\..\..\RimWorldLinux_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
<None Include="..\About\**" />
<None Include="..\Common\Defs\**" />
<None Include="..\Common\Languages\**" />
<None Include="..\Common\Patches\**" />
</ItemGroup>
<ItemGroup>
<Compile Include="DefOf\GeneDefOf.cs" />
<Compile Include="DefOf\HediffDefOf.cs" />
<Compile Include="Hediffs\Infatuo.cs" />
<Compile Include="Helpers\LBTLogger.cs" />
<Compile Include="Helpers\LaborState.cs" />
<Compile Include="DefOf\LetterDefOf.cs" />
<Compile Include="LitterBiotech.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings\LBTSettings.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>cp "$(SolutionDir)Source/obj/Release/$(SolutionName).dll" "$(SolutionDir)1.4/Assemblies"
</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LitterBiotech")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LitterBiotech")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d7d21b4a-1da7-41d8-b202-c58ca8fa62aa")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,54 @@
using UnityEngine;
using Verse;
// If it isn't blatantly obvious, I unabashedly ripped this settings template from RJW, minus the fact that
// I won't be (personally) supporting multiplayer, and it's all in one file - but I digress ...
namespace LitterBiotech
{
class LBTSettingsController : Mod
{
public LBTSettingsController(ModContentPack content) : base(content)
{
GetSettings<LBTSettings>();
}
public override string SettingsCategory()
{
return "LBTSettings".Translate();
}
public override void DoSettingsWindowContents(Rect inRect)
{
LBTSettings.DoWindowContents(inRect);
}
}
public class LBTSettings : ModSettings
{
// For my own sanity, all now and future settings will have a default disabled/false state (at least, that's the plan), and
// the settings name and description should reflect that (not that I'm going to add that many settings, mind you)
public static bool devMode = false;
public static bool regretStealingLovinThoughtDisabled = false;
public static void DoWindowContents(Rect inRect)
{
// Shrink the settings window a bit - don't need to be that w i d e
inRect.width = inRect.width - 400;
inRect.x = inRect.x + 200;
Listing_Standard listingStandard = new Listing_Standard();
listingStandard.Begin(inRect);
listingStandard.Gap(4f);
listingStandard.CheckboxLabeled("EnableLBTDevLogging".Translate(), ref devMode, "EnableLBTDevLoggingDesc".Translate());
listingStandard.Gap(4f);
listingStandard.CheckboxLabeled("RegretStealingLovinThoughtDisabled".Translate(), ref regretStealingLovinThoughtDisabled, "RegretStealingLovinThoughtDisabledDesc".Translate());
listingStandard.End();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref devMode, "EnableLBTDevLogging", devMode, true);
Scribe_Values.Look(ref regretStealingLovinThoughtDisabled, "regretStealingLovinThoughtDisabled", regretStealingLovinThoughtDisabled, true);
}
}
}