Initial upload
This commit is contained in:
parent
feb28b10a4
commit
7585da099c
|
@ -0,0 +1,398 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
Binary file not shown.
|
@ -0,0 +1,116 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<Defs>
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
<defName>Breeder</defName>
|
||||||
|
<label>Breeder</label>
|
||||||
|
<description>{pawn} has given birth so many times that {pawn_possessive} body has adapted to breeding. {pawn_possessive} pregnancies are shorter and produce more offspring.</description>
|
||||||
|
<rarity>ForcedOnly</rarity>
|
||||||
|
<hidden>true</hidden>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthHuman</record>
|
||||||
|
<value>10</value>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthAnimal</record>
|
||||||
|
<value>20</value>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>maxLitterOnBirth</valueName>
|
||||||
|
<multiplier>2.0</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
<defName>Fertile</defName>
|
||||||
|
<label>Fertile</label>
|
||||||
|
<description>{pawn} has unusually high fertility and so is more likely to have children.</description>
|
||||||
|
<conflictingQuirks>
|
||||||
|
<li>Infertile</li>
|
||||||
|
</conflictingQuirks>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.HasFertility"></pawnSelector>
|
||||||
|
<rejectionReason>RaceHasNoFertility</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.HediffAdder">
|
||||||
|
<eventDef>QuirkAddedTo</eventDef>
|
||||||
|
<hediff>IncreasedFertility</hediff>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.HediffRemover">
|
||||||
|
<eventDef>QuirkRemovedFrom</eventDef>
|
||||||
|
<hediff>IncreasedFertility</hediff>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
<defName>Incubator</defName>
|
||||||
|
<label>Incubator</label>
|
||||||
|
<description>{pawn} has birthed so many eggs that {pawn_possessive} body has adapted to handling them. {pawn_possessive} egg incubation speed has increased.</description>
|
||||||
|
<rarity>ForcedOnly</rarity>
|
||||||
|
<hidden>true</hidden>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthEgg</record>
|
||||||
|
<value>100</value>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>maxEggsSize</valueName>
|
||||||
|
<multiplier>2.0</multiplier>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>maxLitterOnBirth</valueName>
|
||||||
|
<multiplier>2.0</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
<defName>Infertile</defName>
|
||||||
|
<label>Infertile</label>
|
||||||
|
<description>{pawn} has unusually low fertility and so is unlikely to have children.</description>
|
||||||
|
<conflictingQuirks>
|
||||||
|
<li>Fertile</li>
|
||||||
|
</conflictingQuirks>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.HasFertility"></pawnSelector>
|
||||||
|
<rejectionReason>RaceHasNoFertility</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.HediffAdder">
|
||||||
|
<eventDef>QuirkAddedTo</eventDef>
|
||||||
|
<hediff>DecreasedFertility</hediff>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.HediffRemover">
|
||||||
|
<eventDef>QuirkRemovedFrom</eventDef>
|
||||||
|
<hediff>DecreasedFertility</hediff>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
<defName>Messy</defName>
|
||||||
|
<label>Messy</label>
|
||||||
|
<description>{pawn} not only produces copious amounts of fluid during sex but {pawn_pronoun} rarely bothers to clean {pawn_possessive}self afterwards.</description>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>cumFilthAmount</valueName>
|
||||||
|
<multiplier>2.0</multiplier>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyOffset">
|
||||||
|
<valueName>cleanAfterFapChance</valueName>
|
||||||
|
<offset>-0.75</offset>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
</Defs>
|
|
@ -0,0 +1,268 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<Defs>
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef Abstract="True" Name="HumanlikeQuirk">
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.IsHumanlike"></pawnSelector>
|
||||||
|
<rejectionReason>NotHumanlike</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Endytophile</defName>
|
||||||
|
<label>Endytophile</label>
|
||||||
|
<description>{pawn} prefers to keep {pawn_possessive} clothes on during sex.</description>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.Clothed"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Exhibitionist</defName>
|
||||||
|
<label>Exhibitionist</label>
|
||||||
|
<description>{pawn} enjoys having sex where others can see.</description>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.Seen"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Gerontophile</defName>
|
||||||
|
<label>Gerontophile</label>
|
||||||
|
<description>{pawn} prefers older partners (55+ on a human scale).</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasHumanScaleAge">
|
||||||
|
<min>55</min>
|
||||||
|
</partnerPreference>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.WithPreferedPartner"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_SetValue">
|
||||||
|
<factorName>ageFactor</factorName>
|
||||||
|
<value>1.0</value>
|
||||||
|
<priority>First</priority>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>ImpregnationFetish</defName>
|
||||||
|
<label>Impregnation fetish</label>
|
||||||
|
<description>{pawn} really likes the idea of someone becoming pregnant. {pawn_pronoun} prefers partners and sex positions where there is a possibility of pregnancy. {pawn_pronoun} doesn't care if {pawn_pronoun} is getting pregnant or {pawn_possessive} partner is as long as babby is formed.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PartnerSelectors.LogicalOr">
|
||||||
|
<parts>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PartnerSelectors.CanImpregnate"></li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PartnerSelectors.CanBeImpregnatedBy"></li>
|
||||||
|
</parts>
|
||||||
|
</partnerPreference>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.LogicalOr">
|
||||||
|
<parts>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.SexSelectors.CanImpregnate"></li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.SexSelectors.CanBeImpregnated"></li>
|
||||||
|
</parts>
|
||||||
|
</sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.PartKindUsageRules_ImpregnationFetish"></li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthHuman</record>
|
||||||
|
<value>10</value>
|
||||||
|
<message>{pawn} has given birth so many times that {pawn_pronoun} developed a fetish for impregnation</message>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthAnimal</record>
|
||||||
|
<value>20</value>
|
||||||
|
<message>{pawn} has given birth so many times that {pawn_pronoun} developed a fetish for impregnation</message>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.Adder_OnRecordExceeding">
|
||||||
|
<eventDef>RecordChanged</eventDef>
|
||||||
|
<record>CountOfBirthEgg</record>
|
||||||
|
<value>100</value>
|
||||||
|
<message>{pawn} has birthed so many eggs that {pawn_pronoun} developed a fetish for impregnation</message>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_ApplyMultiplier">
|
||||||
|
<factorName>bodyFactor</factorName>
|
||||||
|
<multiplier>1.25</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Podophile</defName>
|
||||||
|
<label>Podophile</label>
|
||||||
|
<description>{pawn} really likes feet and prefers foot-related sex acts.</description>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.BySextype">
|
||||||
|
<sextype>Footjob</sextype>
|
||||||
|
</sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.PartKindUsageRules_Static">
|
||||||
|
<partner>
|
||||||
|
<li>
|
||||||
|
<partKind>Foot</partKind>
|
||||||
|
<weightMultiplier>2.0</weightMultiplier>
|
||||||
|
</li>
|
||||||
|
</partner>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>PregnancyFetish</defName>
|
||||||
|
<label>Pregnancy fetish</label>
|
||||||
|
<description>{pawn} prefers partners who are visibly pregnant.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.IsVisiblyPregnant"></partnerPreference>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.WithPreferedPartner"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_ApplyMultiplier">
|
||||||
|
<factorName>bodyFactor</factorName>
|
||||||
|
<multiplier>1.25</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Sapiosexual</defName>
|
||||||
|
<label>Sapiosexual</label>
|
||||||
|
<description>{pawn} prefers smart partners.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PartnerSelectors.LogicalOr">
|
||||||
|
<parts>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait">
|
||||||
|
<trait>Transhumanist</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait">
|
||||||
|
<trait>GreatMemory</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait">
|
||||||
|
<trait>TooSmart</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait" MayRequire="consolidatedtraits.kv.rw">
|
||||||
|
<trait>RCT_Savant</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait" MayRequire="consolidatedtraits.kv.rw">
|
||||||
|
<trait>RCT_Inventor</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait" MayRequire="syrchalis.individuality">
|
||||||
|
<trait>SYR_CreativeThinker</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasSkillLevel">
|
||||||
|
<skill>Intellectual</skill>
|
||||||
|
<minLevel>15</minLevel>
|
||||||
|
</li>
|
||||||
|
</parts>
|
||||||
|
</partnerPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_ApplyMultiplier">
|
||||||
|
<factorName>opinionFactor</factorName>
|
||||||
|
<multiplier>1.4</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Somnophile</defName>
|
||||||
|
<label>Somnophile</label>
|
||||||
|
<description>{pawn} prefers {pawn_possessive} partners to be asleep.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.IsSleeping"></partnerPreference>
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.WithPreferedPartner"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_ApplyMultiplier">
|
||||||
|
<factorName>bodyFactor</factorName>
|
||||||
|
<multiplier>1.25</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Teratophile</defName>
|
||||||
|
<label>Teratophile</label>
|
||||||
|
<description>{pawn} prefers ugly partners. {pawn_pronoun} would also prefer larger and wilder animals if {pawn_pronoun} were into that sort of thing...</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PartnerSelectors.LogicalOr">
|
||||||
|
<parts>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasTrait">
|
||||||
|
<trait>CreepyBreathing</trait>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasDegreeOfTrait">
|
||||||
|
<trait>Beauty</trait>
|
||||||
|
<degree>-1</degree>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasDegreeOfTrait">
|
||||||
|
<trait>Beauty</trait>
|
||||||
|
<degree>-2</degree>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasBodyType">
|
||||||
|
<bodyType>Fat</bodyType>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.IsDisfigured"></li>
|
||||||
|
<li Class="rjwquirks.Modules.Shared.PawnSelectors.HasStatValue">
|
||||||
|
<stat>PawnBeauty</stat>
|
||||||
|
<maxValue>-0.1</maxValue>
|
||||||
|
</li>
|
||||||
|
</parts>
|
||||||
|
</partnerPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.SexAppraisalModifier_SetValue">
|
||||||
|
<factorName>bodyFactor</factorName>
|
||||||
|
<value>1.4</value>
|
||||||
|
<priority>First</priority>
|
||||||
|
</li>
|
||||||
|
<!-- Teratophiles prefer more 'monstrous' partners -->
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>wouldFuckAnimalBodySizeMin</valueName>
|
||||||
|
<multiplier>0.8</multiplier>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>wouldFuckAnimalBodySizeMax</valueName>
|
||||||
|
<multiplier>2.0</multiplier>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>wouldFuckAnimalWildnessModifier</valueName>
|
||||||
|
<multiplier>0.3</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="HumanlikeQuirk">
|
||||||
|
<defName>Vigorous</defName>
|
||||||
|
<label>Vigorous</label>
|
||||||
|
<description>{pawn} is invigorated by sex. {pawn_pronoun} does not get tired as much during sex.</description>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>ticksToNextLovin</valueName>
|
||||||
|
<multiplier>0.8</multiplier>
|
||||||
|
</li>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ValueModifier_ApplyMultiplier">
|
||||||
|
<valueName>reduceRest</valueName>
|
||||||
|
<multiplier>0.5</multiplier>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
</Defs>
|
|
@ -0,0 +1,188 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<!-- There might be too many of these I dunno.
|
||||||
|
People have expressed "special interest" in some of them so I thought
|
||||||
|
it would be cool to have them in the game but since people are weird you end up with a lot of fetishes.-->
|
||||||
|
<Defs>
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef Abstract="True" Name="RaceTagQuirk" ParentName="HumanlikeQuirk">
|
||||||
|
<sexPreference Class="rjwquirks.Modules.Quirks.SexSelectors.WithPreferedPartner"></sexPreference>
|
||||||
|
<comps>
|
||||||
|
<li Class="rjwquirks.Modules.Quirks.Comps.ThoughtAdder_OnSexEvent_Preferred">
|
||||||
|
<eventDef>Orgasm</eventDef>
|
||||||
|
<thought>ThatsMyFetish</thought>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>ChitinLover</defName>
|
||||||
|
<label>Chitin lover</label>
|
||||||
|
<description>{pawn} enjoys the smooth strength of a chitinous exoskeleton. {pawn_pronoun} prefers arachnoid or insectoid partners.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Chitin</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<!-- No fair having a fetish for your own race -->
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Chitin</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>DemonLover</defName>
|
||||||
|
<label>Demon lover</label>
|
||||||
|
<description>{pawn} is after the naughty ones. {pawn_pronoun} prefers {pawn_possessive} partners to come from the literal depths of hell, or at least look the part.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Demon</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Demon</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>FeatherLover</defName>
|
||||||
|
<label>Feather lover</label>
|
||||||
|
<description>{pawn} loves that downy fluff. {pawn_pronoun} prefers avian or dinosaur partners. Because dinosaurs are birds and have feathers, as {pawn_pronoun} will explain at great length if given a chance.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Feathers</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Feathers</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>FurLover</defName>
|
||||||
|
<label>Fur lover</label>
|
||||||
|
<description>{pawn} prefers a partner with a thick, luxurious, snuggly-soft coat of fur.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Fur</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Fur</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>PlantLover</defName>
|
||||||
|
<label>Plant lover</label>
|
||||||
|
<description>{pawn} likes watering plants. If you know what I mean.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Plant</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Plant</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>RobotLover</defName>
|
||||||
|
<label>Robot lover</label>
|
||||||
|
<description>Which is better, 2D or 3D? {pawn} knows that 3D-printed gives you the best of both worlds.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Robot</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Robot</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>ScaleLover</defName>
|
||||||
|
<label>Scale lover</label>
|
||||||
|
<description>Who wouldn't want to fuck a dragon? Definitely not {pawn}. {pawn} wants to fuck a dragon.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Scales</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Scales</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>SkinLover</defName>
|
||||||
|
<label>Skin lover</label>
|
||||||
|
<description>{pawn} prefers {pawn_possessive} partners to have smooth sensitive skin without fur or scales getting in the way. Lucky for {pawn_objective} humans are all over the place.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Skin</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Skin</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Quirks.QuirkDef ParentName="RaceTagQuirk">
|
||||||
|
<defName>SlimeLover</defName>
|
||||||
|
<label>Slime lover</label>
|
||||||
|
<description>Because of their slippery and malleable nature slimes are very, very good at sex. As you will hear over and over if you listen to {pawn} talk for any length of time.</description>
|
||||||
|
<partnerPreference Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Slime</raceTag>
|
||||||
|
</partnerPreference>
|
||||||
|
<ownerRequirements>
|
||||||
|
<li>
|
||||||
|
<pawnSelector Class="rjwquirks.Modules.Shared.PawnSelectors.LogicalNot">
|
||||||
|
<negated Class="rjwquirks.Modules.Shared.PawnSelectors.HasRaceTag">
|
||||||
|
<raceTag>Slime</raceTag>
|
||||||
|
</negated>
|
||||||
|
</pawnSelector>
|
||||||
|
<rejectionReason>QuirkForOwnRace</rejectionReason>
|
||||||
|
</li>
|
||||||
|
</ownerRequirements>
|
||||||
|
</rjwquirks.Modules.Quirks.QuirkDef>
|
||||||
|
</Defs>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
<defName>QuirkAddedTo</defName>
|
||||||
|
<obligatoryArgs>
|
||||||
|
<li>Pawn</li>
|
||||||
|
<li>Quirk</li>
|
||||||
|
</obligatoryArgs>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
<defName>QuirkRemovedFrom</defName>
|
||||||
|
<obligatoryArgs>
|
||||||
|
<li>Pawn</li>
|
||||||
|
<li>Quirk</li>
|
||||||
|
</obligatoryArgs>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
<defName>Orgasm</defName>
|
||||||
|
<obligatoryArgs>
|
||||||
|
<li>SexProps</li>
|
||||||
|
</obligatoryArgs>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
<defName>RecordChanged</defName>
|
||||||
|
<obligatoryArgs>
|
||||||
|
<li>Pawn</li>
|
||||||
|
<li>Record</li>
|
||||||
|
</obligatoryArgs>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
<defName>PawnSexualized</defName>
|
||||||
|
<obligatoryArgs>
|
||||||
|
<li>Pawn</li>
|
||||||
|
</obligatoryArgs>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventDef>
|
||||||
|
|
||||||
|
</Defs>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
<defName>Quirk</defName>
|
||||||
|
<workerClass>rjwquirks.Modules.Quirks.EventHandlers.QuirkRjwEventHandler</workerClass>
|
||||||
|
<handlesEvents>
|
||||||
|
<li>QuirkAddedTo</li>
|
||||||
|
<li>QuirkRemovedFrom</li>
|
||||||
|
</handlesEvents>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
<defName>QuirkSet</defName>
|
||||||
|
<workerClass>rjwquirks.Modules.Quirks.EventHandlers.QuirkSetRjwEventHandler</workerClass>
|
||||||
|
<handlesEvents>
|
||||||
|
<li>Orgasm</li>
|
||||||
|
</handlesEvents>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
<defName>QuirkRecordChanged</defName>
|
||||||
|
<workerClass>rjwquirks.Modules.Quirks.EventHandlers.RecordChangedRjwEventHandler</workerClass>
|
||||||
|
<handlesEvents>
|
||||||
|
<li>RecordChanged</li>
|
||||||
|
</handlesEvents>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
|
||||||
|
<rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
<defName>QuirkGenerator</defName>
|
||||||
|
<workerClass>rjwquirks.Modules.Quirks.EventHandlers.QuirkGenerator</workerClass>
|
||||||
|
<handlesEvents>
|
||||||
|
<li>PawnSexualized</li>
|
||||||
|
</handlesEvents>
|
||||||
|
</rjwquirks.Modules.Shared.Events.RjwEventHandlerDef>
|
||||||
|
|
||||||
|
</Defs>
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<ModMetaData>
|
||||||
|
<name>RJW Quirks</name>
|
||||||
|
<author>Rain</author>
|
||||||
|
<url></url>
|
||||||
|
<supportedVersions>
|
||||||
|
<li>1.4</li>
|
||||||
|
</supportedVersions>
|
||||||
|
<packageId>rain.quirks</packageId>
|
||||||
|
<modDependencies>
|
||||||
|
<li>
|
||||||
|
<packageId>brrainz.harmony</packageId>
|
||||||
|
<displayName>Harmony</displayName>
|
||||||
|
<steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
|
||||||
|
<downloadUrl>https://github.com/pardeike/HarmonyRimWorld/releases/latest</downloadUrl>
|
||||||
|
</li>
|
||||||
|
</modDependencies>
|
||||||
|
<loadAfter>
|
||||||
|
<li>rim.job.world</li>
|
||||||
|
</loadAfter>
|
||||||
|
<incompatibleWith>
|
||||||
|
<li>gregorycurrie.AnimalGenetics</li><!-- Breaks CompHatcher.Hatch preventing eggs hatching -->
|
||||||
|
<li>EdB.PrepareCarefully</li><!-- Hijacks generated/edited pawns at world start, breaks C# hediffs of edited pawns and who knows what else -->
|
||||||
|
<li>EdB.PrepareCarefully.UnofficialPatch</li><!-- Hijacks generated/edited pawns at world start, breaks C# hediffs of edited pawns and who knows what else -->
|
||||||
|
<li>Dalrae.GaramRaceAddon</li><!-- Hijacks pawn generator fucking up pawn genders and who knows what else -->
|
||||||
|
<li>IGNI.LostForest</li><!-- Intentionally breaks rjw jobs, hijacks storyteller to call raids and causes other issues when rjw detected -->
|
||||||
|
<li>Sierra.RT.MedievalTalents</li><!-- Breaks pawn generator/pregnancies, causes pregnancies to instafail -->
|
||||||
|
<li>com.yayo.raceQuestPawn</li><!-- Breaks pawn generator/pregnancies, wrong children outcome-->
|
||||||
|
</incompatibleWith>
|
||||||
|
<description>
|
||||||
|
big peepee sim
|
||||||
|
</description>
|
||||||
|
</ModMetaData>
|
|
@ -0,0 +1,18 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using HugsLib;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks
|
||||||
|
{
|
||||||
|
public class Core : ModBase
|
||||||
|
{
|
||||||
|
// Originally did not use Hugslib, but due to RJW using hugslib I needed to in order for proper patching at correct times. could probably be done with priorities or something but this was easier
|
||||||
|
/*public Core(ModContentPack pack)
|
||||||
|
{
|
||||||
|
//var harmony = new Harmony("rain.quirks");
|
||||||
|
//harmony.PatchAll();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public override string ModIdentifier => "quirk";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Data
|
||||||
|
{
|
||||||
|
public class RaceTags
|
||||||
|
{
|
||||||
|
private readonly static Dictionary<string, RaceTags> tagDatabase = new Dictionary<string, RaceTags>();
|
||||||
|
|
||||||
|
// I only created tags for RaceGroupDef properties that seemed like keywords (like slime) rather than behavior (like oviPregnancy).
|
||||||
|
public readonly static RaceTags Chitin = new RaceTags("Chitin");
|
||||||
|
public readonly static RaceTags Demon = new RaceTags("Demon");
|
||||||
|
public readonly static RaceTags Feathers = new RaceTags("Feathers");
|
||||||
|
public readonly static RaceTags Fur = new RaceTags("Fur");
|
||||||
|
public readonly static RaceTags Plant = new RaceTags("Plant");
|
||||||
|
public readonly static RaceTags Robot = new RaceTags("Robot");
|
||||||
|
public readonly static RaceTags Scales = new RaceTags("Scales");
|
||||||
|
public readonly static RaceTags Skin = new RaceTags("Skin");
|
||||||
|
public readonly static RaceTags Slime = new RaceTags("Slime");
|
||||||
|
|
||||||
|
|
||||||
|
public string Key { get; }
|
||||||
|
|
||||||
|
private RaceTags(string key)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
tagDatabase.Add(key, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(string key, out RaceTags raceTag)
|
||||||
|
{
|
||||||
|
return tagDatabase.TryGetValue(key, out raceTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For backwards compatability only. Shouldn't add more special cases here.
|
||||||
|
/// </summary>
|
||||||
|
public bool DefaultWhenNoRaceGroupDef(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (this == Demon)
|
||||||
|
{
|
||||||
|
return xxx.is_demon(pawn);
|
||||||
|
}
|
||||||
|
else if (this == Slime)
|
||||||
|
{
|
||||||
|
return xxx.is_slime(pawn);
|
||||||
|
}
|
||||||
|
else if (this == Skin)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(CasualSex_Helper), nameof(CasualSex_Helper.GetScore))]
|
||||||
|
public class Patch_CasualSex_Helper
|
||||||
|
{
|
||||||
|
// Edits the "score" of a cell for a pawn to fuck in
|
||||||
|
public static void Postfix(Pawn pawn, IntVec3 cell, Pawn partner, ref int __result)
|
||||||
|
{
|
||||||
|
QuirkSet quirks = pawn.GetQuirks();
|
||||||
|
|
||||||
|
if (quirks.AllQuirks.EnumerableNullOrEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<Pawn> all_pawns = pawn.Map.mapPawns.AllPawnsSpawned.Where(x
|
||||||
|
=> x.Position.DistanceTo(pawn.Position) < 100
|
||||||
|
&& xxx.is_human(x)
|
||||||
|
&& x != pawn
|
||||||
|
&& x != partner
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
// Somnophile code
|
||||||
|
if (partner != null && quirks.Contains(QuirkDefOf.Somnophile))
|
||||||
|
{
|
||||||
|
if (all_pawns.Any(x
|
||||||
|
=> !x.Awake()
|
||||||
|
&& x.Position.DistanceTo(cell) < 6
|
||||||
|
&& GenSight.LineOfSight(cell, x.Position, pawn.Map)
|
||||||
|
))
|
||||||
|
__result += 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exhibitionist code
|
||||||
|
if (quirks.Contains(QuirkDefOf.Exhibitionist))
|
||||||
|
{
|
||||||
|
bool might_be_seen = CasualSex_Helper.MightBeSeen(all_pawns, cell, pawn, partner);
|
||||||
|
Room room = cell.GetRoom(pawn.Map);
|
||||||
|
|
||||||
|
// Readd the 30 score removed in regular RJW
|
||||||
|
__result += 30;
|
||||||
|
// Readd the 100 score taken from being in a doorway in regular RJW
|
||||||
|
__result += 100;
|
||||||
|
|
||||||
|
if (might_be_seen)
|
||||||
|
__result += 5;
|
||||||
|
else
|
||||||
|
__result -= 10;
|
||||||
|
|
||||||
|
if (room.Role == RoomRoleDefOf.Barracks || room.Role == RoomRoleDefOf.PrisonBarracks || room.Role == RoomRoleDefOf.PrisonCell
|
||||||
|
|| room.Role == RoomRoleDefOf.Laboratory || room.Role == RoomRoleDefOf.RecRoom
|
||||||
|
|| room.Role == RoomRoleDefOf.DiningRoom || room.Role == RoomRoleDefOf.Hospital
|
||||||
|
)
|
||||||
|
__result += 15; // Add 15 instead of 10 to counteract the -5 in regular RJW
|
||||||
|
|
||||||
|
Dictionary<int, int> cell_doors = new Dictionary<int, int>();
|
||||||
|
|
||||||
|
var doors = cell_doors.TryGetValue(room.ID);
|
||||||
|
|
||||||
|
if (doors > 1)
|
||||||
|
__result += 7 * doors; // Multiply by 7 instead of 2 to counteract the negative in regular RJW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
// Skips condom code entirely if they have pregnation fetish or similar. RJW used to do this with the same quirk.
|
||||||
|
[HarmonyPatch(typeof(CondomUtility))]
|
||||||
|
public class Patch_CondomUtility
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(CondomUtility.TryUseCondom))]
|
||||||
|
public static bool UseCondomPrefix(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (xxx.is_human(pawn) && pawn.HasQuirk(QuirkDefOf.ImpregnationFetish))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(CondomUtility.GetCondomFromRoom))]
|
||||||
|
public static bool GetCondomPrefix(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (xxx.is_human(pawn) && pawn.HasQuirk(QuirkDefOf.ImpregnationFetish))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Dialog_Sexcard), "SexualityCard")]
|
||||||
|
public static class Patch_Dialog_Sexcard
|
||||||
|
{
|
||||||
|
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
MethodInfo InsertQuirks = AccessTools.Method(typeof(Patch_Dialog_Sexcard), nameof(DrawQuirks));
|
||||||
|
MethodInfo DrawSexuality = AccessTools.Method(typeof(Dialog_Sexcard), "DrawSexuality");
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// When RJW calls draw sexuality we inject our quirk drawing.
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (i.opcode == OpCodes.Call && i.operand as MethodInfo == DrawSexuality)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_2);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldloc_3);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, InsertQuirks);
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawQuirks(Pawn pawn, Rect rect)
|
||||||
|
{
|
||||||
|
QuirkSet quirks = pawn.GetQuirks();
|
||||||
|
rect.y += 24;
|
||||||
|
|
||||||
|
if (quirks == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var quirkString = quirks.AllQuirks
|
||||||
|
.Select(quirk => quirk.Label)
|
||||||
|
.OrderBy(Label => Label)
|
||||||
|
.ToCommaList();
|
||||||
|
|
||||||
|
if ((Current.ProgramState == ProgramState.Playing &&
|
||||||
|
pawn.IsDesignatedHero() && pawn.IsHeroOwner() || Prefs.DevMode) ||
|
||||||
|
Current.ProgramState == ProgramState.Entry)
|
||||||
|
{
|
||||||
|
if (Widgets.ButtonText(rect, "Quirks".Translate() + quirkString, false))
|
||||||
|
DrawQuirkEditMenu(pawn, quirks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Widgets.Label(rect, "Quirks".Translate() + quirkString);
|
||||||
|
|
||||||
|
if (!Mouse.IsOver(rect)) return;
|
||||||
|
|
||||||
|
Widgets.DrawHighlight(rect);
|
||||||
|
|
||||||
|
TooltipHandler.TipRegion(rect, quirks.TipString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DrawQuirkEditMenu(Pawn pawn, QuirkSet quirks)
|
||||||
|
{
|
||||||
|
var quirkDefsAll = DefDatabase<QuirkDef>.AllDefs.OrderBy(def => def.GetLabelFor(pawn));
|
||||||
|
|
||||||
|
var menuOptions = new List<FloatMenuOption>();
|
||||||
|
|
||||||
|
if (RJWSettings.DevMode)
|
||||||
|
menuOptions.Add(new FloatMenuOption("[DEV] Forced Reset", () => quirks.Clear(true)));
|
||||||
|
|
||||||
|
menuOptions.Add(new FloatMenuOption("Reset", () => quirks.Clear()));
|
||||||
|
|
||||||
|
foreach (QuirkDef quirkDef in quirkDefsAll)
|
||||||
|
{
|
||||||
|
if (quirkDef.hidden && !RJWSettings.DevMode && !quirks.Contains(quirkDef))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Quirk quirk = quirks.GetQuirk(quirkDef);
|
||||||
|
FloatMenuOption option;
|
||||||
|
|
||||||
|
if (quirk == null)
|
||||||
|
{
|
||||||
|
AcceptanceReport report = quirks.CanBeAdded(quirkDef);
|
||||||
|
if (report.Accepted)
|
||||||
|
{
|
||||||
|
option = new FloatMenuOption(
|
||||||
|
quirkDef.GetLabelFor(pawn),
|
||||||
|
() => quirks.AddQuirk(quirkDef),
|
||||||
|
mouseoverGuiAction: (Rect rect) => TooltipHandler.TipRegion(rect, quirkDef.GetDescriptionFor(pawn))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (RJWSettings.DevMode)
|
||||||
|
option = new FloatMenuOption($"[DEV]{quirkDef.GetLabelFor(pawn)}: {report.Reason}", () => quirks.AddQuirk(quirkDef, true));
|
||||||
|
else
|
||||||
|
// Game does not call mouseoverGuiAction for the disabled entries
|
||||||
|
option = new FloatMenuOption($"{quirkDef.GetLabelFor(pawn)}: {report.Reason}", null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AcceptanceReport report = quirks.CanBeRemoved(quirkDef);
|
||||||
|
if (report.Accepted)
|
||||||
|
{
|
||||||
|
option = new FloatMenuOption(
|
||||||
|
"- " + quirk.Label,
|
||||||
|
() => quirks.RemoveQuirk(quirk),
|
||||||
|
mouseoverGuiAction: (Rect rect) => TooltipHandler.TipRegion(rect, quirk.Description)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (RJWSettings.DevMode)
|
||||||
|
option = new FloatMenuOption($"- {quirk.Label}: {report.Reason}", () => quirks.RemoveQuirk(quirk, true));
|
||||||
|
else
|
||||||
|
option = new FloatMenuOption($"- {quirk.Label}: {report.Reason}", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuOptions.Add(option);
|
||||||
|
}
|
||||||
|
Find.WindowStack.Add(new FloatMenu(menuOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.DrawNude))]
|
||||||
|
public class Patch_DrawNude
|
||||||
|
{
|
||||||
|
public static bool Prefix(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.HasQuirk(QuirkDefOf.Endytophile))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
/*[HarmonyPatch(typeof(Hediff_BasePregnancy))]
|
||||||
|
public class Patch_Hediff_BasePregnancy
|
||||||
|
{
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch("GenerateBabies")]
|
||||||
|
public static IEnumerable<CodeInstruction> AdjustMaxLitterSize(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (i.opcode == OpCodes.Ldc_R4 && i.operand as string == "0.33333334")
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
if (found && i.opcode == OpCodes.Stloc_S)
|
||||||
|
Log.Warning(i.operand as string);
|
||||||
|
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Hediff_PartBaseArtifical))]
|
||||||
|
public class Patch_Hediff_PartBaseArtifical
|
||||||
|
{
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(nameof(Hediff_PartBaseArtifical.Tick))]
|
||||||
|
public static IEnumerable<CodeInstruction> ChangeMaxEggsSize(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
FieldInfo Pawn = AccessTools.Field(typeof(Hediff_PartBaseArtifical), nameof(Hediff_PartBaseArtifical.pawn));
|
||||||
|
MethodInfo EggSize = AccessTools.Method(typeof(Patch_Hediff_PartBaseArtifical), nameof(EditMaxEggsSize));
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (i.opcode == OpCodes.Ldc_R4 && i.operand as string == "0.0")
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldfld, Pawn);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldloc_3);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, EggSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EditMaxEggsSize(Pawn pawn, float eggsSize)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("maxEggsSize", ref eggsSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Hediff_PartBaseNatural))]
|
||||||
|
public class Patch_Hediff_PartBaseNatural
|
||||||
|
{
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(nameof(Hediff_PartBaseNatural.Tick))]
|
||||||
|
public static IEnumerable<CodeInstruction> ChangeMaxEggsSize(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
FieldInfo Pawn = AccessTools.Field(typeof(Hediff_PartBaseNatural), nameof(Hediff_PartBaseNatural.pawn));
|
||||||
|
MethodInfo EggSize = AccessTools.Method(typeof(Patch_Hediff_PartBaseNatural), nameof(EditMaxEggsSize));
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (i.opcode == OpCodes.Ldc_R4 && i.operand as string == "0.0" && found)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldfld, Pawn);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldloc_3);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, EggSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.opcode == OpCodes.Ldc_R4 && i.operand as string == "0.0")
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EditMaxEggsSize(Pawn pawn, float eggsSize)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("maxEggsSize", ref eggsSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
/*[HarmonyPatch(typeof(JobGiver_Masturbate))]
|
||||||
|
public class Patch_JobGiver_Masturbate
|
||||||
|
{
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch("TryGiveJob")]
|
||||||
|
public static IEnumerable<CodeInstruction> ApplyQuirkToMasturbate(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
MethodInfo Frustrated = AccessTools.Method(typeof(xxx), nameof(xxx.is_frustrated));
|
||||||
|
MethodInfo Apply = AccessTools.Method(typeof(Patch_JobGiver_Masturbate), nameof(ApplyQuirk));
|
||||||
|
var labels = instructions.ElementAt(0).labels.ListFullCopy<Label>();
|
||||||
|
Log.Warning(labels.Count.ToString());
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (i.opcode == OpCodes.Call && i.operand as MethodInfo == Frustrated)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_1);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, Apply);
|
||||||
|
yield return new CodeInstruction(OpCodes.Brtrue_S, labels[4]);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found && i.opcode == OpCodes.Call && i.operand as MethodInfo == Frustrated)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_1);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, Apply);
|
||||||
|
yield return new CodeInstruction(OpCodes.Brtrue_S, labels[5]);
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ApplyQuirk(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
return pawn.HasQuirk(QuirkDefOf.Exhibitionist);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw.Modules.Interactions.Contexts;
|
||||||
|
using rjw.Modules.Interactions.Internals.Implementation;
|
||||||
|
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
|
||||||
|
using rjwquirks.Modules.Interactions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(PartPreferenceDetectorService), nameof(PartPreferenceDetectorService.DetectPartPreferences))]
|
||||||
|
public class Patch_QuirkPartPreference
|
||||||
|
{
|
||||||
|
public static void Prefix(InteractionContext context, IList<IPartPreferenceRule> ____partKindUsageRules)
|
||||||
|
{
|
||||||
|
if (____partKindUsageRules.Any(x => x.GetType() == typeof(QuirksPartKindUsageRule)) || (context.Internals.Submissive.Pawn.GetQuirks() == null || context.Internals.Dominant.Pawn.GetQuirks() == null))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log.Warning(____partKindUsageRules.Count().ToString());
|
||||||
|
____partKindUsageRules.Add(new QuirksPartKindUsageRule());
|
||||||
|
Log.Warning(____partKindUsageRules.Count().ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using RimWorld;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Patch to generate events on record changes
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(Pawn_RecordsTracker))]
|
||||||
|
public static class Patch_RecordsTracker_NotifyRecordChanged
|
||||||
|
{
|
||||||
|
[HarmonyPatch(nameof(Pawn_RecordsTracker.Increment))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void IncrementPostfix(Pawn_RecordsTracker __instance, RecordDef def)
|
||||||
|
{
|
||||||
|
NotifyEvent(__instance.pawn, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(nameof(Pawn_RecordsTracker.AddTo))]
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AddToPostfix(Pawn_RecordsTracker __instance, RecordDef def)
|
||||||
|
{
|
||||||
|
NotifyEvent(__instance.pawn, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void NotifyEvent(Pawn pawn, RecordDef def) => RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.RecordChanged, pawn.Named(RjwEventArgNames.Pawn), def.Named(RjwEventArgNames.Record)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SexAppraiser))]
|
||||||
|
public class Patch_SexAppraiser
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(SexAppraiser.GetMinSizePreference))]
|
||||||
|
public static void AdjustMinSize(Pawn pawn, ref float __result)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("wouldFuckAnimalBodySizeMin", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(SexAppraiser.GetMaxSizePreference))]
|
||||||
|
public static void AdjustMaxSize(Pawn pawn, ref float __result)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("wouldFuckAnimalBodySizeMax", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(SexAppraiser.GetMinSizePreference))]
|
||||||
|
public static void AdjustWildnessModifier(Pawn pawn, ref float __result)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("wouldFuckAnimalWildnessModifier", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch("GetOpinionFactor")]
|
||||||
|
public static void AdjustOpinionFactor(Pawn fucker, Pawn fucked, ref float __result)
|
||||||
|
{
|
||||||
|
if (fucker.GetQuirks() != null)
|
||||||
|
fucker.GetQuirks().ApplySexAppraisalModifiers(fucked, "opinionFactor", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch("GetBodyFactor")]
|
||||||
|
public static void AdjustBodyFactor(Pawn fucker, Pawn fucked, ref float __result)
|
||||||
|
{
|
||||||
|
if (fucker.GetQuirks() != null)
|
||||||
|
fucker.GetQuirks().ApplySexAppraisalModifiers(fucked, "bodyFactor", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch("GetAgeFactor")]
|
||||||
|
public static void AdjustAgeFactor(Pawn fucker, Pawn fucked, int p_age, ref float __result)
|
||||||
|
{
|
||||||
|
if (fucker.GetQuirks() != null)
|
||||||
|
fucker.GetQuirks().ApplySexAppraisalModifiers(fucked, "ageFactor", ref __result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
using HarmonyLib;
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.HarmonyPatches
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SexUtility))]
|
||||||
|
public class Patch_SexUtility
|
||||||
|
{
|
||||||
|
// Increases cum filth generated by pawn
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(SexUtility.CumOutputModifier))]
|
||||||
|
public static void FilthAdder(Pawn pawn, ref float __result)
|
||||||
|
{
|
||||||
|
if(pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("cumFilthAmount", ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change how much the pawn wants to clean post sex
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(nameof(SexUtility.ConsiderCleaning))]
|
||||||
|
static IEnumerable<CodeInstruction> ConsiderCleanup(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
FieldInfo PawnNeeds = AccessTools.Field(typeof(Pawn), nameof(Pawn.needs));
|
||||||
|
MethodInfo Cleanup = AccessTools.Method(typeof(Patch_SexUtility), nameof(CleanupChanceAdjuster));
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
yield return i;
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldloc_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, Cleanup);
|
||||||
|
found = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.opcode == OpCodes.Ldfld && i.operand as FieldInfo == PawnNeeds)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CleanupChanceAdjuster(float chance, Pawn pawn)
|
||||||
|
{
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("cleanAfterFapChance", ref chance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change satisfaction from sex
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(SexUtility.GetExtraSatisfaction))]
|
||||||
|
public static void Satisfaction(SexProps props, ref float __result)
|
||||||
|
{
|
||||||
|
var quirkCount = props.pawn.GetQuirks().GetSatisfiedBySex(props).Count();
|
||||||
|
|
||||||
|
if (quirkCount > 0)
|
||||||
|
{
|
||||||
|
__result += props.pawn.GetQuirks().GetSatisfiedBySex(props).Count() * 0.20f;
|
||||||
|
RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.Orgasm, props.Named(RjwEventArgNames.SexProps), __result.Named(RjwEventArgNames.Satisfaction)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change ticks to next lovin
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(nameof(SexUtility.GenerateMinTicksToNextLovin))]
|
||||||
|
public static IEnumerable<CodeInstruction> ChangeTicksToNextLovin(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
MethodInfo SexDrive = AccessTools.Method(typeof(xxx), nameof(xxx.get_sex_drive));
|
||||||
|
MethodInfo AdjustTicks = AccessTools.Method(typeof(Patch_SexUtility), nameof(AdjustTicksToNextLovin));
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
foreach (var i in instructions)
|
||||||
|
{
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
yield return i;
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldloc_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, AdjustTicks);
|
||||||
|
found = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.opcode == OpCodes.Call && i.operand as MethodInfo == SexDrive)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AdjustTicksToNextLovin(float ticks, Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.GetQuirks() != null)
|
||||||
|
{
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("ticksToNextLovin", ref ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rest adjustments
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
[HarmonyPatch(nameof(SexUtility.reduce_rest))]
|
||||||
|
public static IEnumerable<CodeInstruction> AdjustRest(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
MethodInfo Adjustment = AccessTools.Method(typeof(Patch_SexUtility), nameof(AdjustRestFromQuirk));
|
||||||
|
bool found = false;
|
||||||
|
bool completed = false;
|
||||||
|
|
||||||
|
foreach (CodeInstruction i in instructions)
|
||||||
|
{
|
||||||
|
if (found && !completed)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_1);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call, Adjustment);
|
||||||
|
completed = true;
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.opcode == OpCodes.Dup)
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AdjustRestFromQuirk(Pawn pawn, float x)
|
||||||
|
{
|
||||||
|
if(pawn.GetQuirks() != null)
|
||||||
|
pawn.GetQuirks().ApplyValueModifiers("reduceRest", ref x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
using rjw.Modules.Interactions.Contexts;
|
||||||
|
using rjw.Modules.Interactions.Enums;
|
||||||
|
using rjw.Modules.Interactions.Objects;
|
||||||
|
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
|
||||||
|
using rjw.Modules.Shared;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Interactions
|
||||||
|
{
|
||||||
|
public class QuirksPartKindUsageRule : IPartPreferenceRule
|
||||||
|
{
|
||||||
|
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForDominant(InteractionContext context)
|
||||||
|
{
|
||||||
|
return Enumerable.Concat(
|
||||||
|
ModifierFromPawnQuirks(context.Internals.Dominant, context.Internals.Submissive),
|
||||||
|
ModifierFromPartnerQuirks(context.Internals.Submissive, context.Internals.Dominant)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForSubmissive(InteractionContext context)
|
||||||
|
{
|
||||||
|
return Enumerable.Concat(
|
||||||
|
ModifierFromPawnQuirks(context.Internals.Submissive, context.Internals.Dominant),
|
||||||
|
ModifierFromPartnerQuirks(context.Internals.Dominant, context.Internals.Submissive)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What pawn wants to use because of quirks
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerable<Weighted<LewdablePartKind>> ModifierFromPawnQuirks(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
foreach (var comp in GetQuirkComps(quirkOwner.Pawn))
|
||||||
|
{
|
||||||
|
foreach (var rule in comp.GetModifiersForPawn(quirkOwner, partner))
|
||||||
|
{
|
||||||
|
yield return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What pawn want from partner because of pawn's quirks
|
||||||
|
/// </summary>
|
||||||
|
private IEnumerable<Weighted<LewdablePartKind>> ModifierFromPartnerQuirks(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
foreach (var comp in GetQuirkComps(quirkOwner.Pawn))
|
||||||
|
{
|
||||||
|
foreach (var rule in comp.GetModifiersForPartner(quirkOwner, partner))
|
||||||
|
{
|
||||||
|
yield return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Quirks.Comps.PartKindUsageRules> GetQuirkComps(Pawn pawn)
|
||||||
|
{
|
||||||
|
foreach (var comp in pawn.GetQuirks().AllQuirks.SelectMany(quirk => quirk.def.GetComps<Quirks.Comps.PartKindUsageRules>()))
|
||||||
|
{
|
||||||
|
yield return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
public class CompProperties_QuirkSet : CompProperties
|
||||||
|
{
|
||||||
|
public CompProperties_QuirkSet()
|
||||||
|
{
|
||||||
|
compClass = typeof(QuirkSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for the comps that add quirks to the pawns
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Adder : QuirkComp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// For def load only. Use <see cref="GetMessageFor"/>
|
||||||
|
/// </summary>
|
||||||
|
public string message;
|
||||||
|
public MessageTypeDef messageType;
|
||||||
|
|
||||||
|
protected string MessageTemplate => message ?? parent.description;
|
||||||
|
|
||||||
|
public MessageTypeDef MessageType => messageType ?? MessageTypeDefOf.NeutralEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get adjusted message text to be shown to the user when adding a quirk
|
||||||
|
/// </summary>
|
||||||
|
public string GetMessageFor(Pawn pawn) => MessageTemplate.Formatted(pawn.Named("pawn")).AdjustedFor(pawn).Resolve();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add quirk of comp parent def to the pawn
|
||||||
|
/// </summary>
|
||||||
|
protected void AddQuirkTo(Pawn pawn)
|
||||||
|
{
|
||||||
|
Quirk addedQuirk = pawn.GetQuirks().AddQuirk(parent);
|
||||||
|
|
||||||
|
if (addedQuirk != null)
|
||||||
|
{
|
||||||
|
Messages.Message(GetMessageFor(pawn), pawn, MessageType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventDef == null)
|
||||||
|
{
|
||||||
|
yield return "<eventDef> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Comp to add a quirk when <see cref="record"/> crosses <see cref="value"/>
|
||||||
|
/// </summary>
|
||||||
|
public class Adder_OnRecordExceeding : Adder
|
||||||
|
{
|
||||||
|
public RecordDef record;
|
||||||
|
public float value;
|
||||||
|
|
||||||
|
protected override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||||
|
{
|
||||||
|
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float recordValue = pawn.records?.GetValue(record) ?? 0f;
|
||||||
|
|
||||||
|
if (recordValue >= value && !pawn.HasQuirk(parent))
|
||||||
|
{
|
||||||
|
AddQuirkTo(pawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
yield return "<record> is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == 0f)
|
||||||
|
{
|
||||||
|
yield return "<value> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using rjw;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
// Adds quirk comp to all races
|
||||||
|
[StaticConstructorOnStartup]
|
||||||
|
public static class CompAdder
|
||||||
|
{
|
||||||
|
static CompAdder()
|
||||||
|
{
|
||||||
|
foreach (ThingDef thingDef in DefDatabase<ThingDef>.AllDefs.Where(thingDef =>
|
||||||
|
thingDef.race != null && !thingDef.race.Animal ))
|
||||||
|
{
|
||||||
|
thingDef.comps.Add(new CompProperties_QuirkSet());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Comp to add an <see cref="hediff"/> to the pawn on RJW event
|
||||||
|
/// </summary>
|
||||||
|
public class HediffAdder : QuirkComp
|
||||||
|
{
|
||||||
|
public HediffDef hediff;
|
||||||
|
|
||||||
|
protected override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||||
|
{
|
||||||
|
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pawn.health?.AddHediff(hediff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hediff == null)
|
||||||
|
{
|
||||||
|
yield return "<hediff> is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventDef == null)
|
||||||
|
{
|
||||||
|
yield return "<eventDef> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Comp to remove an <see cref="hediff"/> to the pawn on RJW event
|
||||||
|
/// </summary>
|
||||||
|
public class HediffRemover : QuirkComp
|
||||||
|
{
|
||||||
|
public HediffDef hediff;
|
||||||
|
|
||||||
|
protected override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||||
|
{
|
||||||
|
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hediff existingHediff = pawn.health?.hediffSet?.GetFirstHediffOfDef(hediff);
|
||||||
|
if (existingHediff != null)
|
||||||
|
{
|
||||||
|
pawn.health.RemoveHediff(existingHediff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hediff == null)
|
||||||
|
{
|
||||||
|
yield return "<hediff> is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventDef == null)
|
||||||
|
{
|
||||||
|
yield return "<eventDef> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using rjw.Modules.Interactions.Enums;
|
||||||
|
using rjw.Modules.Interactions.Objects;
|
||||||
|
using rjw.Modules.Shared;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// QuirkComp to affect body part selection when choosing sex interaction
|
||||||
|
/// </summary>
|
||||||
|
public abstract class PartKindUsageRules : QuirkComp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns body parts that pawn prefers because of the quirk
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pawn">Quirk owner</param>
|
||||||
|
/// <param name="partner">Quirk owner's sex partner</param>
|
||||||
|
public abstract IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns body parts that pawn wants partner to use
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pawn">Quirk owner</param>
|
||||||
|
/// <param name="partner">Quirk owner's sex partner</param>
|
||||||
|
public abstract IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using rjw.Modules.Interactions.Enums;
|
||||||
|
using rjw.Modules.Interactions.Objects;
|
||||||
|
using rjw.Modules.Shared;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class PartKindUsageRules_ImpregnationFetish : PartKindUsageRules
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Add desire to use penis if partner has vagina and vise-verse.
|
||||||
|
/// Check of partner's parts is to avoid boosting vagina on futa when partner is female.
|
||||||
|
/// No check of pawn's parts because interaction framework will filter it anyway
|
||||||
|
/// </summary>
|
||||||
|
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
if (!partner.BlockedParts.Contains(LewdablePartKind.Vagina))
|
||||||
|
{
|
||||||
|
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Penis);
|
||||||
|
}
|
||||||
|
if (!partner.BlockedParts.Contains(LewdablePartKind.Penis))
|
||||||
|
{
|
||||||
|
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Vagina);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ask partner to use penis if quirk owner has vagina and provide vagina if owner has penis.
|
||||||
|
/// </summary>
|
||||||
|
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
if (!quirkOwner.BlockedParts.Contains(LewdablePartKind.Vagina))
|
||||||
|
{
|
||||||
|
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Penis);
|
||||||
|
}
|
||||||
|
if (!quirkOwner.BlockedParts.Contains(LewdablePartKind.Penis))
|
||||||
|
{
|
||||||
|
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Vagina);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using rjw.Modules.Interactions.Enums;
|
||||||
|
using rjw.Modules.Interactions.Objects;
|
||||||
|
using rjw.Modules.Shared;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class PartKindUsageRules_Static : PartKindUsageRules
|
||||||
|
{
|
||||||
|
// rjw.Modules.Shared can't be loaded directly because it uses properties.
|
||||||
|
// Probably should change that, but it'll cause more ripples then I'm willing to handle rn
|
||||||
|
public class WeightedDef
|
||||||
|
{
|
||||||
|
public LewdablePartKind partKind;
|
||||||
|
public float weightMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<WeightedDef> self = new List<WeightedDef>();
|
||||||
|
public List<WeightedDef> partner = new List<WeightedDef>();
|
||||||
|
|
||||||
|
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
return self.ConvertAll(ruleDef => new Weighted<LewdablePartKind>(ruleDef.weightMultiplier, ruleDef.partKind));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||||
|
{
|
||||||
|
return this.partner.ConvertAll(ruleDef => new Weighted<LewdablePartKind>(ruleDef.weightMultiplier, ruleDef.partKind));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.NullOrEmpty() && partner.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "Both <self> and <partner> can not be empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public abstract class QuirkComp
|
||||||
|
{
|
||||||
|
public QuirkDef parent;
|
||||||
|
public RjwEventDef eventDef;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notify quirk comp about the RJW event
|
||||||
|
/// </summary>
|
||||||
|
public void NotifyEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (eventDef != null && ev.def == eventDef)
|
||||||
|
{
|
||||||
|
HandleEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle an RJW event. This method called only for events of <see cref="eventDef"/>
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void HandleEvent(RjwEvent ev) { }
|
||||||
|
|
||||||
|
public virtual IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public abstract class SexAppraisalModifier : QuirkComp
|
||||||
|
{
|
||||||
|
public string factorName;
|
||||||
|
public QuirkModifierPriority priority = QuirkModifierPriority.Normal;
|
||||||
|
|
||||||
|
public void TryModifyValue(Pawn quirkOwner, Pawn partner, string factorName, ref float value)
|
||||||
|
{
|
||||||
|
if (this.factorName != factorName)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.partnerPreference?.PartnerSatisfies(quirkOwner, partner) != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyValue(quirkOwner, partner, ref value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (factorName.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "<factorName> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class SexAppraisalModifier_ApplyMultiplier : SexAppraisalModifier
|
||||||
|
{
|
||||||
|
public float multiplier = 1f;
|
||||||
|
|
||||||
|
public override void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value)
|
||||||
|
{
|
||||||
|
value *= multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiplier == 1f)
|
||||||
|
{
|
||||||
|
yield return "<multiplier> is empty or is 1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class SexAppraisalModifier_SetValue : SexAppraisalModifier
|
||||||
|
{
|
||||||
|
public float value;
|
||||||
|
|
||||||
|
public override void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value)
|
||||||
|
{
|
||||||
|
value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value <= 0f)
|
||||||
|
{
|
||||||
|
yield return "<value> must be > 0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for the comps that add thoughts to the pawn
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ThoughtAdder : QuirkComp
|
||||||
|
{
|
||||||
|
public ThoughtDef thought;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add <see cref="thought"/> to the <paramref name="pawn"/>
|
||||||
|
/// </summary>
|
||||||
|
public void ApplyThought(Pawn pawn, Pawn partner) => pawn.needs?.mood?.thoughts?.memories?.TryGainMemory(thought, partner);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thought == null)
|
||||||
|
{
|
||||||
|
yield return "<thought> is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventDef == null)
|
||||||
|
{
|
||||||
|
yield return "<eventDef> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for the comps that add thoughts on RJW event with SexProps argument
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ThoughtAdder_OnSexEvent : ThoughtAdder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Check if thought should be applied
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool ShouldApplyThought(SexProps props);
|
||||||
|
|
||||||
|
protected override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.SexProps, out SexProps props))
|
||||||
|
{
|
||||||
|
ModLog.Error($"{GetType()}.HandleEvent: No SexProps in the event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShouldApplyThought(props))
|
||||||
|
{
|
||||||
|
ApplyThought(props.pawn, props.partner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class ThoughtAdder_OnSexEvent_NonPreferred : ThoughtAdder_OnSexEvent
|
||||||
|
{
|
||||||
|
public override bool ShouldApplyThought(SexProps props) => !parent.IsSatisfiedBySex(props);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class ThoughtAdder_OnSexEvent_Preferred : ThoughtAdder_OnSexEvent
|
||||||
|
{
|
||||||
|
public override bool ShouldApplyThought(SexProps props) => parent.IsSatisfiedBySex(props);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public abstract class ValueModifier : QuirkComp
|
||||||
|
{
|
||||||
|
public string valueName;
|
||||||
|
public QuirkModifierPriority priority = QuirkModifierPriority.Normal;
|
||||||
|
|
||||||
|
public void TryModifyValue(string valueName, ref float value)
|
||||||
|
{
|
||||||
|
if (this.valueName != valueName)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyValue(ref value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void ModifyValue(ref float value);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueName.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "<valueName> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class ValueModifier_ApplyMultiplier : ValueModifier
|
||||||
|
{
|
||||||
|
public float multiplier = 1f;
|
||||||
|
|
||||||
|
public override void ModifyValue(ref float value)
|
||||||
|
{
|
||||||
|
value *= multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiplier == 1f)
|
||||||
|
{
|
||||||
|
yield return "<multiplier> is empty or is 1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.Comps
|
||||||
|
{
|
||||||
|
public class ValueModifier_ApplyOffset : ValueModifier
|
||||||
|
{
|
||||||
|
public float offset;
|
||||||
|
|
||||||
|
public override void ModifyValue(ref float value)
|
||||||
|
{
|
||||||
|
value += offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors(parent))
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == 0f)
|
||||||
|
{
|
||||||
|
yield return "<offset> is empty or is 0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Linq;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||||
|
{
|
||||||
|
public class QuirkGenerator : RjwEventHandler
|
||||||
|
{
|
||||||
|
public override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||||
|
{
|
||||||
|
ModLog.Error($"QuirkGenerator recieved {ev.def}, but event has no '{RjwEventArgNames.Pawn}' argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Generate(pawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate quirks for the pawn.
|
||||||
|
/// Caution: Does not clears existing quirks
|
||||||
|
/// </summary>
|
||||||
|
public static void Generate(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (!pawn.RaceHasSexNeed() || (pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuirkSet quirks = pawn.GetQuirks();
|
||||||
|
|
||||||
|
if (pawn.IsAnimal())
|
||||||
|
{
|
||||||
|
GenerateForAnimal(quirks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GenerateForHumanlike(quirks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rolls an X number between 0 and max quirks setting.
|
||||||
|
/// Tries to add random quirks to the QuirkSet until X are added or out of available quirks.
|
||||||
|
/// </summary>
|
||||||
|
static void GenerateForHumanlike(QuirkSet quirks)
|
||||||
|
{
|
||||||
|
var count = Rand.RangeInclusive(0, RJWPreferenceSettings.MaxQuirks);
|
||||||
|
var availableQuirks = DefDatabase<QuirkDef>.AllDefsListForReading
|
||||||
|
.Where(def => def.rarity != QuirkRarity.ForcedOnly) // Have to earn these
|
||||||
|
.ToArray(); // ToArray to get a shuffleable copy
|
||||||
|
availableQuirks.Shuffle();
|
||||||
|
|
||||||
|
// Some quirks may be hard for a given pawn to indulge in.
|
||||||
|
// For example a female homosexual will have a hard time satisfying an impregnation fetish.
|
||||||
|
// But rimworld is a weird place and you never know what the pawn will be capable of in the future.
|
||||||
|
// We still don't want straight up contradictory results like fertile + infertile.
|
||||||
|
foreach (var quirkDef in availableQuirks)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quirks.CanBeAdded(quirkDef))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count--;
|
||||||
|
quirks.AddQuirk(quirkDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original method rolled 10% chance on 3 hardcoded animal quirks.
|
||||||
|
/// This implementation takes MaxQuirks (3 by default) number of quirks from
|
||||||
|
/// available for animals and rolls 10% chance for each
|
||||||
|
/// </summary>
|
||||||
|
static void GenerateForAnimal(QuirkSet quirks)
|
||||||
|
{
|
||||||
|
int count = RJWPreferenceSettings.MaxQuirks;
|
||||||
|
var availableQuirks = DefDatabase<QuirkDef>.AllDefsListForReading
|
||||||
|
.Where(def => def.rarity != QuirkRarity.ForcedOnly)
|
||||||
|
.ToArray();
|
||||||
|
availableQuirks.Shuffle();
|
||||||
|
|
||||||
|
foreach (var quirkDef in availableQuirks)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quirks.CanBeAdded(quirkDef))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count--;
|
||||||
|
|
||||||
|
if (Rand.Chance(0.1f))
|
||||||
|
{
|
||||||
|
quirks.AddQuirk(quirkDef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handler that passes RJW events to a single quirk
|
||||||
|
/// </summary>
|
||||||
|
public class QuirkRjwEventHandler : RjwEventHandler
|
||||||
|
{
|
||||||
|
public override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Quirk, out Quirk quirk))
|
||||||
|
{
|
||||||
|
ModLog.Error($"QuirkRjwEventHandler recieved {ev.def}, but event has no '{RjwEventArgNames.Quirk}' argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quirk.NotifyEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handler that passes RJW events to all quirks of a pawn
|
||||||
|
/// </summary>
|
||||||
|
public class QuirkSetRjwEventHandler : RjwEventHandler
|
||||||
|
{
|
||||||
|
public override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn);
|
||||||
|
|
||||||
|
if (pawn == null && ev.args.TryGetArg(RjwEventArgNames.SexProps, out SexProps props))
|
||||||
|
{
|
||||||
|
pawn = props.pawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pawn == null)
|
||||||
|
{
|
||||||
|
ModLog.Error($"QuirkSetRjwEventHandler recieved {ev.def}, but event has neither '{RjwEventArgNames.Pawn}' or '{RjwEventArgNames.SexProps}' argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pawn.GetQuirks().NotifyEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handler that passes RJW events a particular comps of an unassigned QuirkDef
|
||||||
|
/// </summary>
|
||||||
|
public class RecordChangedRjwEventHandler : RjwEventHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Records that have associated quirk adder def comps.
|
||||||
|
/// Used to quickly filter out updates of irrelevant records.
|
||||||
|
/// </summary>
|
||||||
|
private static Dictionary<RecordDef, List<Comps.Adder_OnRecordExceeding>> _recordsWithAdder;
|
||||||
|
|
||||||
|
public override void HandleEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
if (ev.def != RjwEventDefOf.RecordChanged)
|
||||||
|
{
|
||||||
|
ModLog.Warning($"RecordChangedRjwEventHandler recieved {ev.def}, but it only handles RecordChanged event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_recordsWithAdder == null)
|
||||||
|
{
|
||||||
|
BuildAdderCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ev.args.TryGetArg(RjwEventArgNames.Record, out RecordDef recordDef))
|
||||||
|
{
|
||||||
|
ModLog.Error($"RecordChangedRjwEventHandler recieved {ev.def}, but event has no '{RjwEventArgNames.Record}' argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_recordsWithAdder.TryGetValue(recordDef, out var comps))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var comp in comps)
|
||||||
|
{
|
||||||
|
// Send message to the def comps directly because the quirk is not assigned to a pawn yet
|
||||||
|
comp.NotifyEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds _recordsWithAdder dictionary
|
||||||
|
/// </summary>
|
||||||
|
private static void BuildAdderCache()
|
||||||
|
{
|
||||||
|
_recordsWithAdder = new Dictionary<RecordDef, List<Comps.Adder_OnRecordExceeding>>();
|
||||||
|
|
||||||
|
foreach (var comp in DefDatabase<QuirkDef>.AllDefs.SelectMany(def => def.GetComps<Comps.Adder_OnRecordExceeding>()))
|
||||||
|
{
|
||||||
|
if (_recordsWithAdder.TryGetValue(comp.record, out var comps))
|
||||||
|
{
|
||||||
|
comps.Add(comp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_recordsWithAdder[comp.record] = new List<Comps.Adder_OnRecordExceeding>() { comp };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class to check if quirk can be assigned to a pawn
|
||||||
|
/// </summary>
|
||||||
|
public class OwnerRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Requirement conditions
|
||||||
|
/// </summary>
|
||||||
|
public IPawnSelector pawnSelector;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Translation key for a displayed reason why quirk can't be assigned to a pawn
|
||||||
|
/// </summary>
|
||||||
|
[NoTranslate]
|
||||||
|
public string rejectionReason;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if pawn satisfies requirement conditions
|
||||||
|
/// </summary>
|
||||||
|
public AcceptanceReport CheckBeforeAdd(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawnSelector?.PawnSatisfies(pawn) == true)
|
||||||
|
{
|
||||||
|
return AcceptanceReport.WasAccepted;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new AcceptanceReport(rejectionReason.Translate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
if (pawnSelector == null)
|
||||||
|
{
|
||||||
|
yield return "<pawnSelector> is empty";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string error in pawnSelector.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rejectionReason.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "<rejectionReason> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Text;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
public class Quirk : IExposable
|
||||||
|
{
|
||||||
|
public QuirkDef def;
|
||||||
|
public Pawn pawn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adjusted for the owner and cached quirk description
|
||||||
|
/// </summary>
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (descriptionCache == null)
|
||||||
|
{
|
||||||
|
// Description bulding is a fairly pricy operation
|
||||||
|
descriptionCache = def.GetDescriptionFor(pawn);
|
||||||
|
}
|
||||||
|
return descriptionCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gender specific quirk label
|
||||||
|
/// </summary>
|
||||||
|
public string Label => def.GetLabelFor(pawn);
|
||||||
|
|
||||||
|
protected string descriptionCache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For save loading only
|
||||||
|
/// </summary>
|
||||||
|
public Quirk() { }
|
||||||
|
|
||||||
|
public Quirk(QuirkDef def, Pawn pawn)
|
||||||
|
{
|
||||||
|
this.def = def;
|
||||||
|
this.pawn = pawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pass RJW event to all comps of this quirk's def
|
||||||
|
/// </summary>
|
||||||
|
public void NotifyEvent(RjwEvent ev) => def.comps.ForEach(comp => comp.NotifyEvent(ev));
|
||||||
|
|
||||||
|
public string TipString()
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
stringBuilder.AppendLine(Label.Colorize(UnityEngine.Color.yellow));
|
||||||
|
stringBuilder.Append(Description);
|
||||||
|
return stringBuilder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExposeData()
|
||||||
|
{
|
||||||
|
Scribe_Defs.Look(ref def, "def");
|
||||||
|
|
||||||
|
if (Scribe.mode == LoadSaveMode.ResolvingCrossRefs && def == null)
|
||||||
|
{
|
||||||
|
def = DefDatabase<QuirkDef>.GetRandom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"Quirk({def})";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Quirks.Comps;
|
||||||
|
using rjwquirks.Modules.Quirks.SexSelectors;
|
||||||
|
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
public class QuirkDef : Def
|
||||||
|
{
|
||||||
|
[MustTranslate]
|
||||||
|
public string labelMale;
|
||||||
|
[MustTranslate]
|
||||||
|
public string labelFemale;
|
||||||
|
public QuirkRarity rarity = QuirkRarity.Common;
|
||||||
|
public bool hidden;
|
||||||
|
public IPartnerSelector partnerPreference;
|
||||||
|
public ISexSelector sexPreference;
|
||||||
|
public List<OwnerRequirement> ownerRequirements = new List<OwnerRequirement>();
|
||||||
|
public List<QuirkComp> comps = new List<QuirkComp>();
|
||||||
|
public List<QuirkDef> conflictingQuirks = new List<QuirkDef>();
|
||||||
|
public List<TraitDef> conflictingTraits = new List<TraitDef>();
|
||||||
|
public List<string> exclusionTags = new List<string>();
|
||||||
|
|
||||||
|
public string GetLabelFor(Gender gender)
|
||||||
|
{
|
||||||
|
if (gender == Gender.Male && !labelMale.NullOrEmpty())
|
||||||
|
{
|
||||||
|
return labelMale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gender == Gender.Female && !labelFemale.NullOrEmpty())
|
||||||
|
{
|
||||||
|
return labelFemale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetLabelFor(Pawn pawn) => GetLabelFor(pawn?.gender ?? Gender.None);
|
||||||
|
|
||||||
|
public IEnumerable<T> GetComps<T>() where T : QuirkComp
|
||||||
|
{
|
||||||
|
for (int i = 0; i < comps.Count; i++)
|
||||||
|
{
|
||||||
|
if (comps[i] is T compT)
|
||||||
|
yield return compT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSatisfiedBySex(SexProps props) => sexPreference?.SexSatisfies(props) == true;
|
||||||
|
|
||||||
|
public bool ConflictsWith(QuirkDef other)
|
||||||
|
{
|
||||||
|
if (other.conflictingQuirks?.Contains(this) == true || conflictingQuirks?.Contains(other) == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (exclusionTags != null && other.exclusionTags != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < exclusionTags.Count; i++)
|
||||||
|
{
|
||||||
|
if (other.exclusionTags.Contains(exclusionTags[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ConflictsWith(TraitDef traitDef)
|
||||||
|
{
|
||||||
|
if (/*traitDef.conflictingQuirks?.Contains(this) == true || */conflictingTraits?.Contains(traitDef) == true)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (exclusionTags != null && traitDef.exclusionTags != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < exclusionTags.Count; i++)
|
||||||
|
{
|
||||||
|
if (traitDef.exclusionTags.Contains(exclusionTags[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetDescriptionFor(Pawn pawn) => description.Formatted(pawn.Named("pawn")).AdjustedFor(pawn).Resolve();
|
||||||
|
|
||||||
|
public override void PostLoad()
|
||||||
|
{
|
||||||
|
base.PostLoad();
|
||||||
|
|
||||||
|
foreach (QuirkComp comp in comps)
|
||||||
|
{
|
||||||
|
comp.parent = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
sexPreference?.SetParent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partnerPreference != null)
|
||||||
|
{
|
||||||
|
foreach (string error in partnerPreference.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sexPreference != null)
|
||||||
|
{
|
||||||
|
foreach (string error in sexPreference.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (OwnerRequirement req in ownerRequirements)
|
||||||
|
{
|
||||||
|
foreach (string error in req.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (QuirkComp comp in comps)
|
||||||
|
{
|
||||||
|
foreach (string error in comp.ConfigErrors(this))
|
||||||
|
{
|
||||||
|
yield return $"{comp.GetType()}: {error}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using RimWorld;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
[DefOf]
|
||||||
|
public static class QuirkDefOf
|
||||||
|
{
|
||||||
|
public static readonly QuirkDef Breeder;
|
||||||
|
public static readonly QuirkDef Endytophile;
|
||||||
|
public static readonly QuirkDef Exhibitionist;
|
||||||
|
public static readonly QuirkDef ImpregnationFetish;
|
||||||
|
public static readonly QuirkDef Incubator;
|
||||||
|
public static readonly QuirkDef Somnophile;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
public enum QuirkModifierPriority
|
||||||
|
{
|
||||||
|
First,
|
||||||
|
High,
|
||||||
|
Normal,
|
||||||
|
Low,
|
||||||
|
Last
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
public enum QuirkRarity
|
||||||
|
{
|
||||||
|
ForcedOnly,
|
||||||
|
Common
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,339 @@
|
||||||
|
using RimWorld;
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Modules.Shared.Events;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A collection/tracker of pawn's quirks
|
||||||
|
/// </summary>
|
||||||
|
public class QuirkSet : ThingComp
|
||||||
|
{
|
||||||
|
protected Pawn pawn;
|
||||||
|
protected List<Quirk> quirks = new List<Quirk>();
|
||||||
|
|
||||||
|
public QuirkSet() { }
|
||||||
|
|
||||||
|
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||||
|
{
|
||||||
|
base.PostSpawnSetup(respawningAfterLoad);
|
||||||
|
|
||||||
|
pawn = parent as Pawn;
|
||||||
|
|
||||||
|
/*if (pawn.kindDef.race.defName.Contains("AIRobot") // No genitalia/sexuality for roombas.
|
||||||
|
|| pawn.kindDef.race.defName.Contains("AIPawn") // ...nor MAI.
|
||||||
|
|| pawn.kindDef.race.defName.Contains("RPP_Bot")
|
||||||
|
|| pawn.kindDef.race.defName.Contains("PRFDrone") // Project RimFactory Revived drones
|
||||||
|
) return;*/
|
||||||
|
|
||||||
|
if (Scribe.mode == LoadSaveMode.LoadingVars && quirks == null)
|
||||||
|
{
|
||||||
|
// Try to restore quirks from old save
|
||||||
|
string quirksave = string.Empty;
|
||||||
|
Scribe_Values.Look(ref quirksave, "RJW_Quirks");
|
||||||
|
if (!quirksave.NullOrEmpty()) // May be pawn really has no quirks
|
||||||
|
{
|
||||||
|
ParseQuirkSave(quirksave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (quirks.NullOrEmpty())
|
||||||
|
{
|
||||||
|
//add random quirk gen and shit later/last
|
||||||
|
AddQuirk(QuirkDefOf.Incubator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// QuirkSet owner
|
||||||
|
/// </summary>
|
||||||
|
public Pawn Pawn => pawn;
|
||||||
|
/// <summary>
|
||||||
|
/// Read-only collection of pawn quirks
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<Quirk> AllQuirks => quirks.AsReadOnly();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to add a quirk of <paramref name="quirkDef"/> to the pawn
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="quirkDef">Def of quirk to add</param>
|
||||||
|
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||||
|
/// <returns>Added quirk or null if addiction failed</returns>
|
||||||
|
public Quirk AddQuirk(QuirkDef quirkDef, bool ignoreChecks = false)
|
||||||
|
{
|
||||||
|
Quirk quirk = new Quirk(quirkDef, pawn);
|
||||||
|
|
||||||
|
if (AddQuirk(quirk, ignoreChecks).Accepted)
|
||||||
|
{
|
||||||
|
return quirk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to add the <paramref name="quirk"/> to the pawn
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="quirk">Quirk to add</param>
|
||||||
|
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||||
|
/// <returns>AcceptanceReport</returns>
|
||||||
|
protected AcceptanceReport AddQuirk(Quirk quirk, bool ignoreChecks = false)
|
||||||
|
{
|
||||||
|
if (!ignoreChecks)
|
||||||
|
{
|
||||||
|
AcceptanceReport report = CanBeAdded(quirk.def);
|
||||||
|
if (!report.Accepted)
|
||||||
|
{
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quirks.Add(quirk);
|
||||||
|
RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.QuirkAddedTo, pawn.Named(RjwEventArgNames.Pawn), quirk.Named(RjwEventArgNames.Quirk)));
|
||||||
|
return AcceptanceReport.WasAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to remove the <paramref name="quirk"/> from the pawn
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="quirk">Quirk to remove</param>
|
||||||
|
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||||
|
/// <returns>AcceptanceReport</returns>
|
||||||
|
public AcceptanceReport RemoveQuirk(Quirk quirk, bool ignoreChecks = false)
|
||||||
|
{
|
||||||
|
if (!ignoreChecks)
|
||||||
|
{
|
||||||
|
AcceptanceReport report = CanBeRemoved(quirk.def);
|
||||||
|
if (!report.Accepted)
|
||||||
|
{
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = quirks.Remove(quirk);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
if (quirks.Contains(quirk))
|
||||||
|
{
|
||||||
|
ModLog.Warning($"Tried to remove {quirk.Label} quirk from {pawn} but failed.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ModLog.Warning($"Trying to remove {quirk.Label} quirk but {pawn} doesn't have it.");
|
||||||
|
}
|
||||||
|
return AcceptanceReport.WasRejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.QuirkRemovedFrom, pawn.Named(RjwEventArgNames.Pawn), quirk.Named(RjwEventArgNames.Quirk)));
|
||||||
|
return AcceptanceReport.WasAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if a quirk of <paramref name="quirkDef"/> can be added to the pawn
|
||||||
|
/// </summary>
|
||||||
|
public AcceptanceReport CanBeAdded(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
if (Contains(quirkDef))
|
||||||
|
{
|
||||||
|
return AcceptanceReport.WasRejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (OwnerRequirement req in quirkDef.ownerRequirements)
|
||||||
|
{
|
||||||
|
AcceptanceReport report = req.CheckBeforeAdd(pawn);
|
||||||
|
if (!report.Accepted)
|
||||||
|
{
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quirks.Find(quirk => quirk.def.ConflictsWith(quirkDef)) is Quirk quirked)
|
||||||
|
{
|
||||||
|
return new AcceptanceReport("ConflictsWithQuirk".Translate(quirked.Label));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pawn?.story?.traits?.allTraits is List<Trait> traits)
|
||||||
|
{
|
||||||
|
foreach (Trait trait in traits)
|
||||||
|
{
|
||||||
|
if (quirks.Find(quirk => quirk.def.ConflictsWith(trait.def)) != null)
|
||||||
|
{
|
||||||
|
return new AcceptanceReport("ConflictsWithTrait".Translate(trait.LabelCap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AcceptanceReport.WasAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if a quirk of <paramref name="quirkDef"/> can be removed from the pawn
|
||||||
|
/// </summary>
|
||||||
|
public AcceptanceReport CanBeRemoved(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
if (!Contains(quirkDef))
|
||||||
|
{
|
||||||
|
return AcceptanceReport.WasRejected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quirkDef.rarity == QuirkRarity.ForcedOnly)
|
||||||
|
{
|
||||||
|
return new AcceptanceReport("CannotRemoveForced".Translate());
|
||||||
|
}
|
||||||
|
|
||||||
|
return AcceptanceReport.WasAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if the pawn has a quirk of <paramref name="quirkDef"/>
|
||||||
|
/// </summary>
|
||||||
|
public bool Contains(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < quirks.Count; i++)
|
||||||
|
{
|
||||||
|
if (quirks[i].def == quirkDef)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a quirk of <paramref name="quirkDef"/>
|
||||||
|
/// </summary>
|
||||||
|
public Quirk GetQuirk(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < quirks.Count; i++)
|
||||||
|
{
|
||||||
|
if (quirks[i].def == quirkDef)
|
||||||
|
{
|
||||||
|
return quirks[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove all quirks from the pawn
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ignoreChecks">even quirks that can't be removed normaly</param>
|
||||||
|
public void Clear(bool ignoreChecks = false) => new List<Quirk>(quirks).ForEach(quirk => RemoveQuirk(quirk, ignoreChecks));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a collection of quirks that are satified by a particular sex act
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<Quirk> GetSatisfiedBySex(SexProps props) => quirks.Where(quirk => quirk.def.IsSatisfiedBySex(props));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pass the RJW event to every quirk of the pawn
|
||||||
|
/// </summary>
|
||||||
|
public void NotifyEvent(RjwEvent ev) => quirks.ForEach(quirk => quirk.NotifyEvent(ev));
|
||||||
|
|
||||||
|
public void ApplySexAppraisalModifiers(Pawn partner, string factorName, ref float value)
|
||||||
|
{
|
||||||
|
foreach (var comp in quirks.SelectMany(quirk => quirk.def.GetComps<Comps.SexAppraisalModifier>())
|
||||||
|
.Where(comp => comp.factorName == factorName)
|
||||||
|
.OrderBy(comp => comp.priority))
|
||||||
|
{
|
||||||
|
comp.TryModifyValue(pawn, partner, factorName, ref value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyValueModifiers(string valueName, ref float value)
|
||||||
|
{
|
||||||
|
foreach (var comp in quirks.SelectMany(quirk => quirk.def.GetComps<Comps.ValueModifier>())
|
||||||
|
.Where(comp => comp.valueName == valueName)
|
||||||
|
.OrderBy(comp => comp.priority))
|
||||||
|
{
|
||||||
|
comp.TryModifyValue(valueName, ref value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyValueModifiers(string valueName, ref int value)
|
||||||
|
{
|
||||||
|
float valueF = value;
|
||||||
|
ApplyValueModifiers(valueName, ref valueF);
|
||||||
|
value = (int)valueF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostExposeData()
|
||||||
|
{
|
||||||
|
base.PostExposeData();
|
||||||
|
|
||||||
|
Scribe_Collections.Look(ref quirks, "allQuirks", LookMode.Deep);
|
||||||
|
|
||||||
|
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||||
|
{
|
||||||
|
if (quirks.RemoveAll((x) => x == null) != 0)
|
||||||
|
{
|
||||||
|
Log.Error("Some quirks were null after loading.");
|
||||||
|
}
|
||||||
|
if (quirks.RemoveAll((x) => x.def == null) != 0)
|
||||||
|
{
|
||||||
|
Log.Error("Some quirks had null def after loading.");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < quirks.Count; i++)
|
||||||
|
{
|
||||||
|
quirks[i].pawn = pawn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TipString()
|
||||||
|
{
|
||||||
|
if (quirks.Count == 0)
|
||||||
|
{
|
||||||
|
return "NoQuirks".Translate();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
foreach (var quirk in quirks.OrderBy(q => q.Label))
|
||||||
|
{
|
||||||
|
stringBuilder.AppendLine(quirk.TipString());
|
||||||
|
stringBuilder.AppendLine("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.ToString().TrimEndNewlines();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fill the QuirkSet from a legacy save string
|
||||||
|
/// </summary>
|
||||||
|
public void ParseQuirkSave(string quirksave)
|
||||||
|
{
|
||||||
|
if (quirksave == "None")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string name in quirksave.Split(','))
|
||||||
|
{
|
||||||
|
if (name.NullOrEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string defName = name.Trim();
|
||||||
|
|
||||||
|
// Old keys doubled as labels. But we can't rely on that becaule def.label can be localized
|
||||||
|
if (defName.Contains(" "))
|
||||||
|
{
|
||||||
|
// To PascalCase
|
||||||
|
defName = defName.Split(' ').Select(part => part.CapitalizeFirst()).Aggregate((x, y) => x + y);
|
||||||
|
}
|
||||||
|
|
||||||
|
QuirkDef def = DefDatabase<QuirkDef>.GetNamed(defName);
|
||||||
|
|
||||||
|
if (def == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
quirks.Add(new Quirk(def, pawn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using rjw;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class BySextype : SexSelector
|
||||||
|
{
|
||||||
|
public xxx.rjwSextype sextype = xxx.rjwSextype.None;
|
||||||
|
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && sexProps.sexType == sextype;
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sextype == xxx.rjwSextype.None)
|
||||||
|
{
|
||||||
|
yield return "<sextype> is not filled or has value \"None\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class CanBeImpregnated : SexSelector
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && PregnancyHelper.CanImpregnate(sexProps.partner, sexProps.pawn, sexProps.sexType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class CanImpregnate : SexSelector
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && PregnancyHelper.CanImpregnate(sexProps.pawn, sexProps.partner, sexProps.sexType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class Clothed : SexSelector
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => !sexProps.pawn.apparel.PsychologicallyNude;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public interface ISexSelector : Shared.IDefPart
|
||||||
|
{
|
||||||
|
void SetParent(QuirkDef quirkDef);
|
||||||
|
bool SexSatisfies(SexProps sexProps);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class LogicalAnd : LogicalMultipart
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (!parts[i].SexSatisfies(sexProps))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public abstract class LogicalMultipart : SexSelector
|
||||||
|
{
|
||||||
|
public List<ISexSelector> parts = new List<ISexSelector>();
|
||||||
|
|
||||||
|
public override void SetParent(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
base.SetParent(quirkDef);
|
||||||
|
parts.ForEach(selector => selector.SetParent(quirkDef));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.Count < 2)
|
||||||
|
{
|
||||||
|
yield return "<parts> should have at least 2 elements";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
foreach (string error in part.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using rjw;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class LogicalNot : SexSelector
|
||||||
|
{
|
||||||
|
public ISexSelector negated;
|
||||||
|
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => !negated.SexSatisfies(sexProps);
|
||||||
|
|
||||||
|
public override void SetParent(QuirkDef quirkDef)
|
||||||
|
{
|
||||||
|
base.SetParent(quirkDef);
|
||||||
|
negated.SetParent(quirkDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negated == null)
|
||||||
|
{
|
||||||
|
yield return "<negated> is empty";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string error in negated.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class LogicalOr : LogicalMultipart
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (parts[i].SexSatisfies(sexProps))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using rjw;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class Seen : SexSelector
|
||||||
|
{
|
||||||
|
// Current implementation works only if somebody sees pawn exactly at the moment quirks are evaluated
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && SexSeen(sexProps);
|
||||||
|
|
||||||
|
public static bool SexSeen(SexProps sexProps)
|
||||||
|
{
|
||||||
|
bool isZoophile = xxx.is_zoophile(sexProps.pawn);
|
||||||
|
return sexProps.pawn.Map.mapPawns.AllPawnsSpawned.Any(x =>
|
||||||
|
x != sexProps.pawn
|
||||||
|
&& x != sexProps.partner
|
||||||
|
&& !x.Dead
|
||||||
|
&& (isZoophile || !xxx.is_animal(x))
|
||||||
|
&& x.CanSee(sexProps.pawn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using rjw;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public abstract class SexSelector : ISexSelector
|
||||||
|
{
|
||||||
|
protected QuirkDef parentDef;
|
||||||
|
|
||||||
|
public abstract bool SexSatisfies(SexProps sexProps);
|
||||||
|
|
||||||
|
public virtual void SetParent(QuirkDef quirkDef) => parentDef = quirkDef;
|
||||||
|
|
||||||
|
public virtual IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using rjw;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||||
|
{
|
||||||
|
public class WithPreferedPartner : SexSelector
|
||||||
|
{
|
||||||
|
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && parentDef.partnerPreference?.PartnerSatisfies(sexProps.pawn, sexProps.partner) == true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Copy of the HistoryEvent.
|
||||||
|
/// Made it it's own thing because it use cases are different
|
||||||
|
/// </summary>
|
||||||
|
public struct RjwEvent
|
||||||
|
{
|
||||||
|
public RjwEventDef def;
|
||||||
|
public SignalArgs args;
|
||||||
|
|
||||||
|
public RjwEvent(RjwEventDef def, params NamedArgument[] args)
|
||||||
|
{
|
||||||
|
this.def = def;
|
||||||
|
this.args = new SignalArgs(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
public static class RjwEventArgNames
|
||||||
|
{
|
||||||
|
public static readonly string Pawn = "Pawn";
|
||||||
|
public static readonly string SexProps = "SexProps";
|
||||||
|
public static readonly string Quirk = "Quirk";
|
||||||
|
public static readonly string Record = "Record";
|
||||||
|
public static readonly string Satisfaction = "Satisfaction";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
public class RjwEventDef : Def
|
||||||
|
{
|
||||||
|
public List<string> obligatoryArgs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using RimWorld;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
[DefOf]
|
||||||
|
public static class RjwEventDefOf
|
||||||
|
{
|
||||||
|
public static readonly RjwEventDef QuirkAddedTo;
|
||||||
|
public static readonly RjwEventDef QuirkRemovedFrom;
|
||||||
|
public static readonly RjwEventDef Orgasm;
|
||||||
|
public static readonly RjwEventDef RecordChanged;
|
||||||
|
public static readonly RjwEventDef PawnSexualized;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
public abstract class RjwEventHandler
|
||||||
|
{
|
||||||
|
public RjwEventHandlerDef def;
|
||||||
|
public abstract void HandleEvent(RjwEvent ev);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
public class RjwEventHandlerDef : Def
|
||||||
|
{
|
||||||
|
public Type workerClass;
|
||||||
|
public List<RjwEventDef> handlesEvents;
|
||||||
|
|
||||||
|
private RjwEventHandler _worker;
|
||||||
|
|
||||||
|
public RjwEventHandler Worker
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_worker == null)
|
||||||
|
{
|
||||||
|
_worker = (RjwEventHandler)Activator.CreateInstance(workerClass);
|
||||||
|
_worker.def = this;
|
||||||
|
}
|
||||||
|
return _worker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workerClass == null)
|
||||||
|
{
|
||||||
|
yield return "<workerClass> is empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handlesEvents == null || handlesEvents.Count == 0)
|
||||||
|
{
|
||||||
|
yield return "<handlesEvents> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
using RimWorld;
|
||||||
|
using rjw.Modules.Shared.Logs;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.Events
|
||||||
|
{
|
||||||
|
public static class RjwEventManager
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<RjwEventDef, List<RjwEventHandler>> _handlers = BuildHandlerDictionary();
|
||||||
|
private static readonly ILog _logger = LogManager.GetLogger("RjwEventManager");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Routes RJW events to the relevant event handlers based on the def subscriptions
|
||||||
|
/// </summary>
|
||||||
|
public static void NotifyEvent(RjwEvent ev)
|
||||||
|
{
|
||||||
|
//implement own settings later
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
_logger.Message($"RJW Event {ev.def}{SignalArgsToString(ev.args)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_handlers.TryGetValue(ev.def, out List<RjwEventHandler> eventHandlers))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
// Since event args are filled in C#, no reason to waste time checking them outside of the actual mod developement
|
||||||
|
CheckObligatoryArgs(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (RjwEventHandler handler in eventHandlers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler.HandleEvent(ev);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// suppress exceptions so one bad mod wouldn't break everything
|
||||||
|
_logger.Error($"Handler exception when handling {ev.def}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<RjwEventDef, List<RjwEventHandler>> BuildHandlerDictionary()
|
||||||
|
{
|
||||||
|
Dictionary<RjwEventDef, List<RjwEventHandler>> handlers = new Dictionary<RjwEventDef, List<RjwEventHandler>>();
|
||||||
|
|
||||||
|
foreach (RjwEventHandlerDef handlerDef in DefDatabase<RjwEventHandlerDef>.AllDefsListForReading)
|
||||||
|
{
|
||||||
|
foreach (RjwEventDef eventDef in handlerDef.handlesEvents)
|
||||||
|
{
|
||||||
|
if (handlers.ContainsKey(eventDef))
|
||||||
|
{
|
||||||
|
handlers[eventDef].Add(handlerDef.Worker);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlers[eventDef] = new List<RjwEventHandler> { handlerDef.Worker };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckObligatoryArgs(RjwEvent ev)
|
||||||
|
{
|
||||||
|
foreach (string argName in ev.def.obligatoryArgs)
|
||||||
|
{
|
||||||
|
if (!ev.args.TryGetArg(argName, out _))
|
||||||
|
{
|
||||||
|
_logger.Error($"Got a {ev.def} event without the obligatory argument '{argName}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SignalArgsToString(SignalArgs args)
|
||||||
|
{
|
||||||
|
StringBuilder message = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var arg in args.Args)
|
||||||
|
{
|
||||||
|
message.Append(", ");
|
||||||
|
message.Append(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This interface designates that a class is ment to be included in a def and
|
||||||
|
/// instantiated by the Rimworld when the def is loaded
|
||||||
|
/// </summary>
|
||||||
|
public interface IDefPart
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Needed to be called explicidly in the def's ConfigErrors()
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<string> ConfigErrors();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Partner selectors are similar to the pawn selectors, but can define relations between two pawns.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPartnerSelector : IDefPart
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the partner satisfies all XML-defined conditions in relation to the pawn.
|
||||||
|
/// Non-commutative
|
||||||
|
/// </summary>
|
||||||
|
bool PartnerSatisfies(Pawn pawn, Pawn partner);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Pawn selectors are designed to provide a flexible way to define pawn requirements in the defs
|
||||||
|
/// </summary>
|
||||||
|
public interface IPawnSelector : IDefPart
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if pawn satisfies all XML-defined conditions
|
||||||
|
/// </summary>
|
||||||
|
bool PawnSatisfies(Pawn pawn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using rjw;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class CanBeImpregnatedBy : PartnerSelector
|
||||||
|
{
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => PregnancyHelper.CanImpregnate(partner, pawn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using rjw;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class CanImpregnate : PartnerSelector
|
||||||
|
{
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => PregnancyHelper.CanImpregnate(pawn, partner);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class HasOneOfRelations : PartnerSelector
|
||||||
|
{
|
||||||
|
public List<PawnRelationDef> relations;
|
||||||
|
|
||||||
|
private HashSet<PawnRelationDef> relationsHashSet;
|
||||||
|
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||||
|
{
|
||||||
|
if (relationsHashSet == null)
|
||||||
|
{
|
||||||
|
relationsHashSet = new HashSet<PawnRelationDef>(relations);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<PawnRelationDef> pawnRelations = pawn.GetRelations(partner);
|
||||||
|
|
||||||
|
if (pawnRelations.EnumerableNullOrEmpty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relationsHashSet.Overlaps(pawnRelations))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relations.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "<relations> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class LogicalAnd : LogicalMultipart
|
||||||
|
{
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||||
|
{
|
||||||
|
if (partner == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (!parts[i].PartnerSatisfies(pawn, partner))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public abstract class LogicalMultipart : PartnerSelector
|
||||||
|
{
|
||||||
|
public List<IPartnerSelector> parts = new List<IPartnerSelector>();
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.Count < 2)
|
||||||
|
{
|
||||||
|
yield return "<parts> should have at least 2 elements";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
foreach (string error in part.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class LogicalNot : PartnerSelector
|
||||||
|
{
|
||||||
|
public IPartnerSelector negated;
|
||||||
|
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => !negated.PartnerSatisfies(pawn, partner);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negated == null)
|
||||||
|
{
|
||||||
|
yield return "<negated> is empty";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string error in negated.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public class LogicalOr : LogicalMultipart
|
||||||
|
{
|
||||||
|
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||||
|
{
|
||||||
|
if (partner == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (parts[i].PartnerSatisfies(pawn, partner))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||||
|
{
|
||||||
|
public abstract class PartnerSelector : IPartnerSelector
|
||||||
|
{
|
||||||
|
public abstract bool PartnerSatisfies(Pawn pawn, Pawn partner);
|
||||||
|
|
||||||
|
public virtual IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasBodyType : PawnSelector
|
||||||
|
{
|
||||||
|
public BodyTypeDef bodyType;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.bodyType == bodyType;
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bodyType == null)
|
||||||
|
{
|
||||||
|
yield return "<bodyType> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasDegreeOfTrait : PawnSelector
|
||||||
|
{
|
||||||
|
public TraitDef trait;
|
||||||
|
public int degree = 0;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.traits?.HasTrait(trait, degree) == true;
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trait == null)
|
||||||
|
{
|
||||||
|
yield return "<trait> is empty";
|
||||||
|
}
|
||||||
|
else if (trait.degreeDatas.Find(d => d.degree == degree) == null)
|
||||||
|
{
|
||||||
|
yield return $"{trait.defName} has no data for a degree {degree}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using rjw;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasFertility : PawnSelector
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.RaceHasFertility();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasGender : PawnSelector
|
||||||
|
{
|
||||||
|
public Gender gender = Gender.None;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.gender == gender;
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gender == Gender.None)
|
||||||
|
{
|
||||||
|
yield return "<gender> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
using rjw;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasHumanScaleAge : PawnSelector
|
||||||
|
{
|
||||||
|
public int min = 0;
|
||||||
|
public int max = 1000;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn)
|
||||||
|
{
|
||||||
|
int humanScaleAge = SexUtility.ScaleToHumanAge(pawn);
|
||||||
|
return min <= humanScaleAge && humanScaleAge <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min == 0 && max == 1000)
|
||||||
|
{
|
||||||
|
yield return "<min> and/or <max> should be filled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using rjw;
|
||||||
|
using rjwquirks.Data;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasRaceTag : PawnSelector
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// For def load only. Use RaceTag property
|
||||||
|
/// </summary>
|
||||||
|
public string raceTag;
|
||||||
|
|
||||||
|
public RaceTags RaceTag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RaceTags.TryParse(raceTag, out RaceTags tag))
|
||||||
|
return tag;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.HasRaceTag(RaceTag);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raceTag.NullOrEmpty())
|
||||||
|
{
|
||||||
|
yield return "<raceTag> is empty";
|
||||||
|
}
|
||||||
|
else if (!RaceTags.TryParse(raceTag, out _))
|
||||||
|
{
|
||||||
|
yield return $"\"{raceTag}\" is not a valid RaceTag";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasSkillLevel : PawnSelector
|
||||||
|
{
|
||||||
|
public SkillDef skill;
|
||||||
|
public int minLevel = 0;
|
||||||
|
public int maxLevel = 200; // mods can unlock levels past 20
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn)
|
||||||
|
{
|
||||||
|
int skillLevel = pawn.skills?.GetSkill(skill)?.levelInt ?? -1;
|
||||||
|
return minLevel <= skillLevel && skillLevel <= maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skill == null)
|
||||||
|
{
|
||||||
|
yield return "<skill> is empty";
|
||||||
|
}
|
||||||
|
if (minLevel == 0 && maxLevel == 200)
|
||||||
|
{
|
||||||
|
yield return "<minLevel> and/or <maxLevel> should be filled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasStatValue : PawnSelector
|
||||||
|
{
|
||||||
|
public StatDef stat;
|
||||||
|
public float minValue = float.MinValue;
|
||||||
|
public float maxValue = float.MaxValue;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn)
|
||||||
|
{
|
||||||
|
float statValue = pawn.GetStatValue(stat);
|
||||||
|
return minValue <= statValue && statValue <= maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat == null)
|
||||||
|
{
|
||||||
|
yield return "<stat> is empty";
|
||||||
|
}
|
||||||
|
if (minValue == float.MinValue && maxValue == float.MaxValue)
|
||||||
|
{
|
||||||
|
yield return "<minValue> and/or <maxValue> should be filled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class HasTrait : PawnSelector
|
||||||
|
{
|
||||||
|
public TraitDef trait;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.traits?.HasTrait(trait) == true;
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trait == null)
|
||||||
|
{
|
||||||
|
yield return "<trait> is empty";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class IsDisfigured : PawnSelector
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => RelationsUtility.IsDisfigured(pawn);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class IsHumanlike : PawnSelector
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn?.RaceProps?.Humanlike == true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class IsSleeping : PawnSelector
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => !pawn.Awake();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
using rjw;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class IsVisiblyPregnant : PawnSelector
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => pawn.IsVisiblyPregnant();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class LogicalAnd : LogicalMultipart
|
||||||
|
{
|
||||||
|
public override bool PawnSatisfies(Pawn pawn)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < parts.Count; i++)
|
||||||
|
{
|
||||||
|
if (!parts[i].PawnSatisfies(pawn))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public abstract class LogicalMultipart : PawnSelector
|
||||||
|
{
|
||||||
|
public List<IPawnSelector> parts = new List<IPawnSelector>();
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.Count < 2)
|
||||||
|
{
|
||||||
|
yield return "<parts> should have at least 2 elements";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
foreach (string error in part.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||||
|
{
|
||||||
|
public class LogicalNot : PawnSelector
|
||||||
|
{
|
||||||
|
public IPawnSelector negated;
|
||||||
|
|
||||||
|
public override bool PawnSatisfies(Pawn pawn) => !negated.PawnSatisfies(pawn);
|
||||||
|
|
||||||
|
public override IEnumerable<string> ConfigErrors()
|
||||||
|
{
|
||||||
|
foreach (string error in base.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negated == null)
|
||||||
|
{
|
||||||
|
yield return "<negated> is empty";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string error in negated.ConfigErrors())
|
||||||
|
{
|
||||||
|
yield return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue