code:
аборт
сексуальные практики
уход
возраст согласия
оргазм
анальный секс
гениталии животных
спаривание животных
анонимный секс
аромантичность
асексуальность
девочки
автоэротизм
самоотсос
бидоны
бороды
сексизм
секс с животными
большие попки
бифобия
бисексуальность
укусы
повязки на глаза
смазка
модификации тела
бондаж
титилис
сиськи
попки
пассивов
утяжки для груди
рост груди
гипертрофированная грудь
пытки над грудью
вылизывание груди
грудь
контроль дыхания партнёра
осеменители
буккаке
стриптизёрши-кролики
анальные пробки
пик-ак
кошкодевочки
воздержание
пояс верности
измена
гигантские сиськи
любителей толстушек
клитор
ублажение члена
ношение ошейника
религиозные взгляды на секс
неуверенное согласие
согласие
контрацептивы
межвидовой секс
сперма
куни
киберсекс
деднейминг
разврат
демисексуальность
доминация
двойное проникновение
двойные стандарты
драг квин
эджинг
съедобное бельё
согласие с энтузиазмом
эротическое прерывание секса
эротическое отшлёпывание
эротическая щекотка
эротика
эксгибиционизм
внебрачный секс
сидение на лице
оскорбления за вес
женское доминирование
девушки без секса
феменизм
теория феменизма
фетиши
финансовая доминация
фингеринг
игры с огнём
фистинг
флирт
раздевание по принуждению
предварительные ласки
дружба с "бонусами"
фурри
фурсьюты
фута
гэнг-бэнг
гей-радар
ГЕЙ-меры
геи
гендерная идентичность
гендерная нейтральность
гендерные роли
нарушение гендерных ролей
гигантомастия
гоккун
приятная боль
групповой секс
мастурбация рукой
предел терпения боли
гарем
хентай
гетеросексуальность
гомофобия
Гомосексуальность
большие сиськи
гипербеременность
отшлёпывание
импотенция
инбридинг
инцелы
инцест
вызов лактации
измена
половой акт
межкультурный секс
межкультурный секс
интерсекциональность
межвидовой брак
межвидовые отношения
непринятие своей гомосексуальности
игры с ножом
лактация
феминные лесбиянки
смазка
макрофилия
занятие любовью
менсплейнинг
мазохизм
мастурбация
механофилия
микрофилия
мисгендеринг
моногамность
взаимная мастурбация
накадаши
некрофилия
игры с иголкой
нетораре
нетори
милые парни
девятидоллоровая купюра
секс без пенетрации
пытка носа
нудизм
нагота
нимфомания
нимфоманки
объективизация
свободный брак
оральный секс
оргазмы
оргии
откладка яиц
член в штанине
любители боли
пайзури
пансексуальность
парафилия
переход
патриархат
пеггинг
пенисы
пассивная лесбиянка
полиаморность
пони-бои
пони-гёрл
порно-логика
неприкрытые плечи
порно
потенция
беременность
привилегии
подбор лифчика
проститутки
проституция
культура воздержания
пытка вагины
квир-теория
радикальный феменизм
изнасилование
культура изнасилований
фантазии об изнасиловании
секс для развлечения
боль в заднице
римминг
связывание верёвкой
садизм
садомазохизм
безопасный секс
стоп-слово
соблазнение
игра с чувствами
подчинение со службой
секс
сексуальная привлекательность
сексуальное образование
позиции в сексе
секс-игрушки
торговля сексом
секс-боты
кайфовый секс
сексизм
сексуальное насилие
возбуждение
сексуальное преступление
сексуальные предпочтения
сексуальные дисфункицц
сексуальные фантазии
мораль в сексе
мексуальная ориентация
секс-рабство
сексуальная стимуляция
ориентация
шибари
сиська-вид-с-боку
секс во сне
спит
содомия
мягкие ограничения
отшлёпывание
ЗППП
стриптиз
подчинение
сабспейс
купальники
свингинг
свитчинг
табу
технофилия
тератофилия
яички
подглядывание
тройнички
пытка груди
вести в сексе снизу
токсичная маскулинность
транс-эксклюзивный феменизм
фантазии о трансформации
transmisogyny
трансмизогиния
транссексуальность
трансвеститы
фетиши
твинки
вымя
фетиш на поглощение вагиной
обвинение жертвы
девственность
виртуальный секс
фетиш на поедание
вуайеризм
игры с воском
влажные сны
ксенофилия
яой
йифф
юри
зоофилия


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/DutyDef[defName="BI_DefendAndExpandHive"]</xpath>

				<xpath>Defs/DutyDef[defName="BI_DefendAndExpandHive"]/thinkNode/subNodes/li[@Class="ThinkNode_ChancePerHour_Constant"]</xpath>
				<value>

				</value>

		</operations>
	</Operation>
</Patch>

license: mit


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName != "Human" and defName != "MechanicalCentipede" and defName != "Scyther" and defName != "Lancer" and defName != "Pikeman"]/corePart/parts</xpath>
		<value>

				<def>Genitals</def>
				<coverage>0.005</coverage>
				<height>Bottom</height>
				<depth>Outside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName != "Human" and defName != "MechanicalCentipede" and defName != "Scyther" and defName != "Lancer" and defName != "Pikeman"]/corePart/parts</xpath>
		<value>

				<def>Chest</def>
				<coverage>0.02</coverage>
				<height>Top</height>
				<depth>Outside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName != "Human" and defName != "MechanicalCentipede" and defName != "Scyther" and defName != "Lancer" and defName != "Pikeman"]/corePart/parts</xpath>
		<value>

				<def>Anus</def>
				<coverage>0.001</coverage>
				<height>Bottom</height>
				<depth>Inside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Human"]/corePart/parts</xpath>
		<value>

				<def>Genitals</def>
				<coverage>0.005</coverage>
				<height>Bottom</height>
				<depth>Outside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Human"]/corePart/parts</xpath>
		<value>

				<def>Chest</def>
				<coverage>0.02</coverage>
				<height>Top</height>
				<depth>Outside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Human"]/corePart/parts</xpath>
		<value>

				<def>Anus</def>
				<coverage>0.001</coverage>
				<height>Bottom</height>
				<depth>Inside</depth>
				<groups>

Torso

				</groups>

		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>

<Patch>
	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "MechanicalCentipede"]/corePart/parts/li[def = "MechanicalCentipedeBodySecondRing"]/parts</xpath>
		<value>

				<def>MechGenitals</def>
				<coverage>0.001</coverage>
				<depth>Inside</depth>

		</value>
	</Operation>
	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Lancer"]/corePart/parts</xpath>
		<value>

				<def>MechGenitals</def>
				<coverage>0.001</coverage>
				<depth>Inside</depth>

		</value>
	</Operation>
	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Scyther"]/corePart/parts</xpath>
		<value>

				<def>MechGenitals</def>
				<coverage>0.001</coverage>
				<depth>Inside</depth>

		</value>
	</Operation>
	<Operation Class="PatchOperationAdd">
		<xpath>Defs/BodyDef[defName = "Pikeman"]/corePart/parts</xpath>
		<value>

				<def>MechGenitals</def>
				<coverage>0.001</coverage>
				<depth>Inside</depth>

		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
	<!--Rape prisoners in NonPlayerHome-->
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendBase"]/thinkNode/subNodes/li[@Class="ThinkNode_ForbidOutsideFlagRadius"]/subNodes/li[@Class="ThinkNode_Subtree"]</xpath>
		<value>
			<li Class="rjw.JobGiver_AIRapePrisoner" />
		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "AssaultColony"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "AssaultColony"]/thinkNode/subNodes/li[@Class="JobGiver_AITrashColonyClose"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "Sapper"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "Defend"]/thinkNode/subNodes/li[@Class="ThinkNode_ForbidOutsideFlagRadius"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendBase"]/thinkNode/subNodes/li[@Class="JobGiver_AIDefendPoint"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "HuntEnemiesIndividual"]/thinkNode/subNodes/li[@Class="JobGiver_AIFightEnemies"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendAndExpandHive"]/thinkNode/subNodes/li[@Class="ThinkNode_Tagger"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/DutyDef[defName = "DefendHiveAggressively"]/thinkNode/subNodes/li[@Class="JobGiver_HiveDefense"]</xpath>
		<value>

		</value>
	</Operation>
	<Operation Class="PatchOperationInsert">
		<xpath>Defs/ThinkTreeDef[defName="MentalStateNonCritical"]/thinkRoot[@Class="ThinkNode_Tagger"]/subNodes/li[stateClass="MentalState_Manhunter"]/subNodes/li[@Class="ThinkNode_Priority"]/subNodes/li[@Class="JobGiver_Manhunter"]</xpath>
		<value>

		</value>
	</Operation>

</Patch>


code:
<?xml version="1.0" encoding="utf-8"?>
<Patch>
  <Operation Class="PatchOperationFindMod">
    <mods>

[NL] Facial Animation - WIP

    </mods>
    <match Class="PatchOperationSequence">
      <success>Always</success>
      <operations>

          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/targetJobs</xpath>
          <success>Always</success>
          <value>

RJW_Masturbate

GettinBred

Bestiality

BestialityForFemale

ViolateCorpse

Quickie

GettingQuickie

GettinRaped

JoinInBed

GettinLoved

GettinLicked

GettinSucked

WhoreIsServingVisitors

          </value>

          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="WaitCombat" or defName="Wait_Combat_Rare"]/targetJobs</xpath>
          <success>Always</success>
          <value>

RapeComfortPawn

RandomRape

RapeEnemy

          </value>

          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="StandAndBeSociallyActive"]/targetJobs</xpath>
          <success>Always</success>
          <value>

WhoreInvitingVisitors

          </value>

          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Wear" or defName="Wear2" or defName="Wear3"]/targetJobs</xpath>
          <success>Always</success>
          <value>

CleanSelf

StruggleInBondageGear

          </value>

          <mods>

Rimworld-Animations

          </mods>
          <match Class="PatchOperationSequence">
            <success>Always</success>
            <operations>

                <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[1]/headOffset</xpath>
                <success>Always</success>

                <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin"]/animationFrames/li[2]/headOffset</xpath>
                <success>Always</success>

                <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin"]/animationFrames/li[3]/headOffset</xpath>
                <success>Always</success>

				<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/targetJobs</xpath>
				<success>Always</success>
				<value>

JoinInBedAnimation

GettinLovedAnimation

				</value>

            </operations>
          </match>

      </operations>
    </match>
  </Operation>
</Patch>


code:
<?xml version="1.0" encoding="UTF-8"?>
<Patch>

	<Operation Class="PatchOperationFindMod">
		<mods>

Royalty

		</mods>
		<match Class="PatchOperationAdd">
			<xpath>/Defs/HediffDef[defName="LoveEnhancer"]</xpath>
			<value>
				<stages>

						<statOffsets>
							<SexAbility>0.1</SexAbility>
							<SexSatisfaction>0.15</SexSatisfaction>
						</statOffsets>

				</stages>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationFindMod">
		<mods>

Royalty

		</mods>
		<match Class="PatchOperationAdd">
			<xpath>/Defs/HediffDef[defName="AestheticShaper"]/stages/li/statOffsets</xpath>
			<value>
				<SexAbility>0.05</SexAbility>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationFindMod">
		<mods>

Royalty

		</mods>
		<match Class="PatchOperationAdd">
			<xpath>/Defs/HediffDef[defName="PsychicReader"]/stages/li/statOffsets</xpath>
			<value>
				<SexAbility>0.1</SexAbility>
			</value>
		</match>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThinkTreeDef[defName="MentalStateCritical"]/thinkRoot[@Class="ThinkNode_Tagger"]/subNodes</xpath>
		<value>

				<state>RandomRape</state>
				<subNodes>

						<need>Rest</need>
						<threshold>0.05</threshold>
						<invert>true</invert>
						<subNodes>

						</subNodes>

						<minPriority>0.5</minPriority>
						<subNodes>

								<subNodes>

								</subNodes>

						</subNodes>

				</subNodes>

		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/TraitDef[defName="Prude"]</xpath>

				<xpath>Defs/TraitDef[defName="Nymphomaniac"]/conflictingTraits</xpath>
				<value>

Prude

				</value>

				<xpath>Defs/TraitDef[defName="Prude"]/conflictingTraits</xpath>
				<value>

Nymphomaniac

				</value>

				<xpath>Defs/TraitDef[defName="Prude"]/degreeDatas/li</xpath>
				<value>
					<statOffsets>
						<SexFrequency>-0.3</SexFrequency>
					</statOffsets>
				</value>

		</operations>
	</Operation>

	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/TraitDef[defName="Faithful"]</xpath>

				<xpath>Defs/TraitDef[defName="Nymphomaniac"]/conflictingTraits</xpath>
				<value>

Faithful

				</value>

				<xpath>Defs/TraitDef[defName="Faithful"]/conflictingTraits</xpath>
				<value>

Nymphomaniac

				</value>

		</operations>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Nimble"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Nimble"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<SexAbility>0.2</SexAbility>
					<Vulnerability>-0.1</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Nimble"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<SexAbility>0.2</SexAbility>
				<Vulnerability>-0.1</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Bloodlust"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Bloodlust"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<Vulnerability>-0.1</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Bloodlust"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<Vulnerability>-0.1</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Tough"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Tough"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<Vulnerability>-0.4</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Tough"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<Vulnerability>-0.4</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="TooSmart"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="TooSmart"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<Vulnerability>-0.3</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="TooSmart"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<Vulnerability>-0.3</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Wimp"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Wimp"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<Vulnerability>0.2</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Wimp"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<Vulnerability>0.2</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Masochist"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Masochist"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<Vulnerability>0.3</Vulnerability>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Masochist"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<Vulnerability>0.3</Vulnerability>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="Ascetic"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Ascetic"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<SexFrequency>-0.3</SexFrequency>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="Ascetic"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<SexFrequency>-0.3</SexFrequency>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationConditional">
		<xpath>Defs/TraitDef[defName="BodyPurist"]/degreeDatas/li/statOffsets</xpath>
		<nomatch Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="BodyPurist"]/degreeDatas/li</xpath>
			<value>
				<statOffsets>
					<SexFrequency>-0.1</SexFrequency>
				</statOffsets>
			</value>
		</nomatch>
		<match Class="PatchOperationAdd">
			<xpath>Defs/TraitDef[defName="BodyPurist"]/degreeDatas/li/statOffsets</xpath>
			<value>
				<SexFrequency>-0.1</SexFrequency>
			</value>
		</match>
	</Operation>

	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/TraitDef[defName="Asexual"]</xpath>

				<xpath>Defs/TraitDef[defName="Necrophiliac"]/conflictingTraits</xpath>
				<value>

Asexual

				</value>

				<xpath>Defs/TraitDef[defName="Nymphomaniac"]/conflictingTraits</xpath>
				<value>

Asexual

				</value>

				<xpath>Defs/TraitDef[defName="Rapist"]/conflictingTraits</xpath>
				<value>

Asexual

				</value>

				<xpath>Defs/TraitDef[defName="Zoophile"]/conflictingTraits</xpath>
				<value>

Asexual

				</value>

				<xpath>Defs/TraitDef[defName="Asexual"]/conflictingTraits</xpath>
				<value>

Necrophiliac

Nymphomaniac

Rapist

Zoophile

				</value>

		</operations>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>

	<Operation Class="PatchOperationAdd">
		<xpath>Defs/ThingDef[@Name="AnimalThingBase"]/recipes</xpath>
		<value>

DeterminePregnancy

RJW_AbortionHuman

RJW_AbortionBeast

RJW_AbortionMech

RJW_HackMech

RJW_RemoveRestraints

RJW_RemoveCocoon

		</value>
	</Operation>
</Patch>


code:
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
  <Operation Class="PatchOperationAdd">
    <xpath>Defs/RulePackDef[defName = "GlobalUtility"]/include</xpath>
    <value>

TalkTopicsSex

    </value>
  </Operation>

  <Operation Class="PatchOperationAdd">
    <xpath>Defs/InteractionDef[defName = "DeepTalk"]/logRulesInitiator/rulesStrings</xpath>
    <value>

subject(p=0.24)->[TalkTopicSex]

    </value>
  </Operation>

  <Operation Class="PatchOperationAdd">
    <xpath>Defs/InteractionDef[defName = "Chitchat"]/logRulesInitiator/rulesStrings</xpath>
    <value>

r_logentry(p=0.12)->[INITIATOR_nameDef] and [RECIPIENT_nameDef] [talkedabout] [TalkTopicSex].

r_logentry(p=0.12)->[INITIATOR_nameDef] [talkedabout] [TalkTopicSex] with [RECIPIENT_nameDef].

r_logentry(p=0.24)->[INITIATOR_nameDef] [commentedabout] [TalkTopicSex] to [RECIPIENT_nameDef].

    </value>
  </Operation>
</Patch>


code:
<Patch>
	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/ThoughtDef[defName="HarmedMe"]/nullifyingTraits</xpath>
				<value>

Masochist

				</value>

		</operations>
	</Operation>
</Patch>


code:
<Patch>
	<Operation Class="PatchOperationSequence">
		<success>Always</success>
		<operations>

				<xpath>Defs/ThoughtDef[defName="ObservedLayingCorpse"]/nullifyingTraits</xpath>
				<value>

Necrophiliac

				</value>

				<xpath>Defs/ThoughtDef[defName="ObservedLayingRottingCorpse"]/nullifyingTraits</xpath>
				<value>

Necrophiliac

				</value>

		</operations>
	</Operation>
</Patch>


code:
root=true

[*.{cs,xml}]
indent_style = tab


code:
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RimJobWorld")]
[assembly: AssemblyDescription("Adult mod for Rimworld")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Community Project")]
[assembly: AssemblyProduct("RimJobWorld")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c2825019-7f0b-456d-85a3-479c1a2a8805")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
[assembly: AssemblyVersion("1.0.0.0")]


code:
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Lib.Harmony" version="2.0.2" targetFramework="net472" />
  <package id="RimWorld.MultiplayerAPI" version="0.2.0" targetFramework="net472" />
  <package id="UnlimitedHugs.Rimworld.HugsLib" version="8.0.0" targetFramework="net472" />
</packages>


code:
/*
Core versions of scripts addapted for Greater Good
*/

using System;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using RimWorld.Planet;
using Verse;
using rjw;

namespace rjw_CORE_EXPOSED
{
	public static class JobDriver_Lovin
	{
		public static readonly SimpleCurve LovinIntervalHoursFromAgeCurve = new SimpleCurve
		{
			new CurvePoint(1f,  12f),
			new CurvePoint(16f, 6f),
			new CurvePoint(22f, 9f),
			new CurvePoint(30f, 12f),
			new CurvePoint(50f, 18f),
			new CurvePoint(75f, 24f)
		};
	}

	// used in Vulnerability StatDef calculation
	public class SkillNeed_BaseBonus : SkillNeed
	{
		private float baseValue = 0.5f;

		private float bonusPerLevel = 0.05f;

		public override float ValueFor(Pawn pawn)
		{
			if (pawn.skills == null)
			{
				return 1f;
			}
			int level = pawn.skills.GetSkill(this.skill).Level;
			// remove melee bonus for pawns: downed, sleeping/resting/lying, wearing armbinder
			if (pawn.Downed || pawn.GetPosture() != PawnPosture.Standing || pawn.health.hediffSet.HasHediff(DefDatabase<HediffDef>.GetNamedSilentFail("Armbinder")))
				//|| pawn.health.hediffSet.HasHediff(HediffDef.Named("Yoke")) || pawn.health.hediffSet.HasHediff(HediffDef.Named("BoundHands")))
				level = 0;
			return this.ValueAtLevel(level);
		}

		private float ValueAtLevel(int level)
		{
			return this.baseValue + this.bonusPerLevel * (float)level;
		}

		public override IEnumerable<string> ConfigErrors()
		{
			foreach (string error in base.ConfigErrors())
			{
				yield return error;
			}
			for (int i = 1; i <= 20; i++)
			{
				float factor = this.ValueAtLevel(i);
				if (factor <= 0f)
				{
					yield return "SkillNeed yields factor < 0 at skill level " + i;
				}
			}
		}
	}

	public static class LovePartnerRelationUtility
	{
		public static float LovinMtbSinglePawnFactor(Pawn pawn)
		{
			float num = 1f;
			num /= 1f - pawn.health.hediffSet.PainTotal;
			float efficiency = pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness);
			if (efficiency < 0.5f)
			{
				num /= efficiency * 2f;
			}

			if (!pawn.RaceProps.Humanlike)
			{
				return num * 4f;
			}
			if (RimWorld.LovePartnerRelationUtility.ExistingLovePartner(pawn) != null)
			{
				num *= 2f; //This is a factor which makes pawns with love partners less likely to do fappin/random raping/rapingCP/bestiality/necro.
			}
			else if (pawn.gender == Gender.Male)
			{
				num /= 1.25f; //This accounts for single men
			}
			return num / GenMath.FlatHill(0.0001f, 8f, 13f, 28f, 50f, 0.15f, pawn.ageTracker.AgeBiologicalYearsFloat);//this needs to be changed
		}
	}

	public static class MedicalRecipesUtility
	{
		public static bool IsCleanAndDroppable(Pawn pawn, BodyPartRecord part)
		{
			return IsClean(pawn, part) && part.def.spawnThingOnRemoved != null;
		}
		//TODO: add check if hediff are bad?
		public static bool IsClean(Pawn pawn, BodyPartRecord part)
		{
			//in vanilla Hediff = always bad?
			return !pawn.Dead && !(from x in pawn.health.hediffSet.hediffs
									where (x.Part == part)
									select x).Any<Hediff>();
		}

		public static bool IsViolationOnPawn(Pawn pawn, BodyPartRecord part, Faction billDoerFaction)
		{
			return pawn.Faction != billDoerFaction || HealthUtility.PartRemovalIntent(pawn, part) == BodyPartRemovalIntent.Harvest;
		}

		public static void RestorePartAndSpawnAllPreviousParts(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			SpawnNaturalPartIfClean(pawn, part, pos, map);
			SpawnThingsFromHediffs(pawn, part, pos, map);
			pawn.health.RestorePart(part, null, true);
		}

		// always false since rjw uses hediffs for genitals, thus its always dirty
		public static Thing SpawnNaturalPartIfClean(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			if (MedicalRecipesUtility.IsCleanAndDroppable(pawn, part))
			{
				//normal/rimworld parts
				return GenSpawn.Spawn(part.def.spawnThingOnRemoved, pos, map);
			}
			return null;
		}

		/// <summary>
		/// spawn rjw parts after operation
		/// </summary>
		/// <param name="pawn"></param>
		/// <param name="part"></param>
		/// <param name="pos"></param>
		/// <param name="map"></param>
		public static void SpawnThingsFromHediffs(Pawn pawn, BodyPartRecord part, IntVec3 pos, Map map)
		{
			if (!pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Contains(part))
			{
				return;
			}
			if (pawn.Dead)
			{
				return;
			}
			IEnumerable<Hediff> enumerable = from x in pawn.health.hediffSet.hediffs
											 where x.Part == part
											 select x;
			//RJW parts and other implants?
			foreach (Hediff current in enumerable)
			{
				if (current.def.spawnThingOnRemoved != null)
				{
					//Thing thing = GenSpawn.Spawn(current.def.spawnThingOnRemoved, pos, map);

					//spawn thing
					GenSpawn.Spawn(SexPartAdder.recipePartRemover(current), pos, map);
				}
			}
			//spawn sub parts? not sure why would it call itself but w/e
			for (int i = 0; i < part.parts.Count; i++)
			{
				MedicalRecipesUtility.SpawnThingsFromHediffs(pawn, part.parts[i], pos, map);
			}
		}
	}

	public class Recipe_RemoveBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				IEnumerable<BodyPartRecord> parts = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined);
				foreach (BodyPartRecord part in parts)
				{
					if (pawn.health.hediffSet.HasDirectlyAddedPartFor(part))
					{
						yield return part;
					}
					if (MedicalRecipesUtility.IsCleanAndDroppable(pawn, part))
					{
						yield return part;
					}
					if (part != pawn.RaceProps.body.corePart && part.def.canSuggestAmputation && pawn.health.hediffSet.hediffs.Any((Hediff d) => !(d is Hediff_Injury) && d.def.isBad && d.Visible && d.Part == part))
					{
						yield return part;
					}
				}
			}
		}

		private const int ViolationGoodwillImpact = -15;

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			bool flag = MedicalRecipesUtility.IsClean(pawn, part);
			bool flag2 = MedicalRecipesUtility.IsViolationOnPawn(pawn, part, Faction.OfPlayer);
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				MedicalRecipesUtility.SpawnNaturalPartIfClean(pawn, part, billDoer.Position, billDoer.Map);
				MedicalRecipesUtility.SpawnThingsFromHediffs(pawn, part, billDoer.Position, billDoer.Map);
			}
			DamageDef surgicalCut = DamageDefOf.SurgicalCut;
			float amount = 99999f;
			float armorPenetration = 999f;
			pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
			if (flag)
			{
				if (pawn.Dead)
				{
					ThoughtUtility.GiveThoughtsForPawnExecuted(pawn, PawnExecutionKind.OrganHarvesting);
				}
				ThoughtUtility.GiveThoughtsForPawnOrganHarvested(pawn);
			}
			if (flag2 && pawn.Faction != null && billDoer != null && billDoer.Faction != null)
			{
				Faction faction = pawn.Faction;
				Faction faction2 = billDoer.Faction;
				string reason = "GoodwillChangedReason_RemovedBodyPart".Translate(part.LabelShort);
				GlobalTargetInfo? lookTarget = pawn;
				faction.TryAffectGoodwillWith(faction2, ViolationGoodwillImpact, true, true, reason, lookTarget);
			}
		}

		public override string GetLabelWhenUsedOn(Pawn pawn, BodyPartRecord part)
		{
			if (pawn.RaceProps.IsMechanoid || pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part))
			{
				return RecipeDefOf.RemoveBodyPart.LabelCap;
			}
			BodyPartRemovalIntent bodyPartRemovalIntent = HealthUtility.PartRemovalIntent(pawn, part);
			if (bodyPartRemovalIntent == BodyPartRemovalIntent.Harvest)
			{
				return "Harvest".Translate();
			}
			if (bodyPartRemovalIntent != BodyPartRemovalIntent.Amputate)
			{
				throw new InvalidOperationException();
			}
			if (part.depth == BodyPartDepth.Inside)
			{
				return "RemoveOrgan".Translate();
			}
			return "Amputate".Translate();
		}
	}

	public class Recipe_InstallOrReplaceBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}

		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				//ModLog.Message("Recipe_InstallOrReplaceBodyPart Recipe: " + recipe.defName);

				// For all parts listed in the recipe
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					// Grab the recipe part
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];

					// For all parts on the pawn
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						// Grab the pawn part
						BodyPartRecord record = bpList[j];

						// If the recipe part and pawn part match
						if (record.def == part)
						{
							// Grab all pawn hediffs for natural and artificial parts that are on the current pawn body part
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record && (x is Hediff_PartBaseNatural || x is Hediff_PartBaseArtifical)
														select x;

							//ModLog.Message("Recipe_InstallOrReplaceBodyPart GetPartsToApplyOn: Pawn=" + pawn.Name + " Part=" + record.Label + ", diffs.Count=" + diffs.Count<Hediff>() + ", First Diff=" + diffs.First<Hediff>().def.defName + " recipe.addsHediff=" + recipe.addsHediff.defName);

							// If the pawn doesn't have exactly 1 diff for that part OR the first diff found is not the one being added by the recipe
							//if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								//ModLog.Message("Diff Matched.  Recipe parent=" + record.parent?.Label);

								// If this is the base body OR the pawn has the parent body part of the recipe part
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									//ModLog.Message("Parent Found.  PartOrAnyAncestorHasDirectlyAddedParts=" + pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) + ", HasDirectlyAddedPartFor=" + pawn.health.hediffSet.HasDirectlyAddedPartFor(record));

									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										//ModLog.Message("Recipe: " + recipe.defName + "Applies to: " + record.Label + " of " + pawn.Name);
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					DamageDef surgicalCut = DamageDefOf.SurgicalCut;
					float amount = 99999f;
					float armorPenetration = 999f;
					pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				MedicalRecipesUtility.RestorePartAndSpawnAllPreviousParts(pawn, part, billDoer.Position, billDoer.Map);
			}
			//pawn.health.AddHediff(recipe.addsHediff, part, null, null);

			pawn.health.AddHediff(SexPartAdder.recipePartAdder(recipe, pawn, part, ingredients), part, null, null);
		}
	}

	public class Recipe_AddBodyPart : Recipe_Surgery
	{
		public virtual bool blocked(Pawn p)
		{
			return false;
		}
		public override IEnumerable<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
		{
			if (!blocked(pawn))
			{
				for (int i = 0; i < recipe.appliedOnFixedBodyParts.Count; i++)
				{
					BodyPartDef part = recipe.appliedOnFixedBodyParts[i];
					List<BodyPartRecord> bpList = pawn.RaceProps.body.AllParts;
					for (int j = 0; j < bpList.Count; j++)
					{
						BodyPartRecord record = bpList[j];
						if (record.def == part)
						{
							IEnumerable<Hediff> diffs = from x in pawn.health.hediffSet.hediffs
														where x.Part == record && (x is Hediff_PartBaseNatural || x is Hediff_PartBaseArtifical)
														select x;

							// If the pawn doesn't have exactly 1 diff for that part OR the first diff found is not the one being added by the recipe
							//if (diffs.Count<Hediff>() != 1 || diffs.First<Hediff>().def != recipe.addsHediff)
							{
								if (record.parent == null || pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(record.parent))
								{
									if (!pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(record) || pawn.health.hediffSet.HasDirectlyAddedPartFor(record))
									{
										yield return record;
									}
								}
							}
						}
					}
				}
			}
		}

		public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
		{
			if (billDoer != null)
			{
				if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
				{
					DamageDef surgicalCut = DamageDefOf.SurgicalCut;
					float amount = 99999f;
					float armorPenetration = 999f;
					pawn.TakeDamage(new DamageInfo(surgicalCut, amount, armorPenetration, -1f, null, part, null, DamageInfo.SourceCategory.ThingOrUnknown, null));
					return;
				}
				TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[]
				{
					billDoer,
					pawn
				});
				//pawn.health.AddHediff(recipe.addsHediff, part, null, null);

				pawn.health.AddHediff(SexPartAdder.recipePartAdder(recipe, pawn, part, ingredients), part, null, null);
			}
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;

using System;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using RimWorld.Planet;
using Verse;

namespace rjw_CORE_EXPOSED
{
	[StaticConstructorOnStartup]
	public static class rjwHealthCardUtility
	{
		public static Vector2 scrollPosition = Vector2.zero;

		public static float scrollViewHeight = 0f;

		public static bool highlight = true;

		public static bool onOperationTab = false;

		public static Vector2 billsScrollPosition = Vector2.zero;

		public static float billsScrollHeight = 1000f;

		public static bool showAllHediffs = false;

		public static bool showHediffsDebugInfo = false;

		public const float TopPadding = 20f;

		public const float ThoughtLevelHeight = 25f;

		public const float ThoughtLevelSpacing = 4f;

		public const float IconSize = 20f;

		public static readonly Color HighlightColor = new Color(0.5f, 0.5f, 0.5f, 1f);

		public static readonly Color StaticHighlightColor = new Color(0.75f, 0.75f, 0.85f, 1f);

		public static readonly Color VeryPoorColor = new Color(0.4f, 0.4f, 0.4f);

		public static readonly Color PoorColor = new Color(0.55f, 0.55f, 0.55f);

		public static readonly Color WeakenedColor = new Color(0.7f, 0.7f, 0.7f);

		public static readonly Color EnhancedColor = new Color(0.5f, 0.5f, 0.9f);

		public static readonly Color MediumPainColor = new Color(0.9f, 0.9f, 0f);

		public static readonly Color SeverePainColor = new Color(0.9f, 0.5f, 0f);

		public static readonly Texture2D BleedingIcon = ContentFinder<Texture2D>.Get("UI/Icons/Medical/Bleeding", true);

		public static List<ThingDef> tmpMedicineBestToWorst = new List<ThingDef>();

		public static void DrawPawnHealthCard(Rect outRect, Pawn pawn, bool allowOperations, bool showBloodLoss, Thing thingForMedBills)
		{
			if (pawn.Dead && allowOperations)
			{
				Log.Error("Called DrawPawnHealthCard with a dead pawn and allowOperations=true. Operations are disallowed on corpses.", false);
				allowOperations = false;
			}
			outRect = outRect.Rounded();
			Rect rect = new Rect(outRect.x, outRect.y, outRect.width * 0.375f, outRect.height).Rounded();
			Rect rect2 = new Rect(rect.xMax, outRect.y, outRect.width - rect.width, outRect.height);
			rect.yMin += 11f;
			rjwHealthCardUtility.DrawHealthSummary(rect, pawn, allowOperations, thingForMedBills);
			rjwHealthCardUtility.DrawHediffListing(rect2.ContractedBy(10f), pawn, showBloodLoss);
		}

		public static void DrawHealthSummary(Rect rect, Pawn pawn, bool allowOperations, Thing thingForMedBills)
		{
			GUI.color = Color.white;
			if (!allowOperations)
			{
				rjwHealthCardUtility.onOperationTab = false;
			}
			Widgets.DrawMenuSection(rect);
			List<TabRecord> list = new List<TabRecord>();
			list.Add(new TabRecord("HealthOverview".Translate(), delegate
			{
				rjwHealthCardUtility.onOperationTab = false;
			}, !rjwHealthCardUtility.onOperationTab));
			if (allowOperations)
			{
				string label = (!pawn.RaceProps.IsMechanoid) ? "MedicalOperationsShort".Translate(pawn.BillStack.Count) : "MedicalOperationsMechanoidsShort".Translate(pawn.BillStack.Count);
				list.Add(new TabRecord(label, delegate
				{
					rjwHealthCardUtility.onOperationTab = true;
				}, rjwHealthCardUtility.onOperationTab));
			}
			TabDrawer.DrawTabs(rect, list, 200f);
			rect = rect.ContractedBy(9f);
			GUI.BeginGroup(rect);
			float curY = 0f;
			Text.Font = GameFont.Medium;
			GUI.color = Color.white;
			Text.Anchor = TextAnchor.UpperCenter;
			if (rjwHealthCardUtility.onOperationTab)
			{
				PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.MedicalOperations, KnowledgeAmount.FrameDisplayed);
				curY = rjwHealthCardUtility.DrawMedOperationsTab(rect, pawn, thingForMedBills, curY);
			}
			else
			{
				curY = rjwHealthCardUtility.DrawOverviewTab(rect, pawn, curY);
			}
			Text.Font = GameFont.Small;
			GUI.color = Color.white;
			Text.Anchor = TextAnchor.UpperLeft;
			GUI.EndGroup();
		}

		public static void DrawHediffListing(Rect rect, Pawn pawn, bool showBloodLoss)
		{
			GUI.color = Color.white;
			if (Prefs.DevMode && Current.ProgramState == ProgramState.Playing)
			{
				rjwHealthCardUtility.DoDebugOptions(rect, pawn);
			}
			GUI.BeginGroup(rect);
			float lineHeight = Text.LineHeight;
			Rect outRect = new Rect(0f, 0f, rect.width, rect.height - lineHeight);
			Rect viewRect = new Rect(0f, 0f, rect.width - 16f, rjwHealthCardUtility.scrollViewHeight);
			Rect rect2 = rect;
			if (viewRect.height > outRect.height)
			{
				rect2.width -= 16f;
			}
			Widgets.BeginScrollView(outRect, ref rjwHealthCardUtility.scrollPosition, viewRect, true);
			GUI.color = Color.white;
			float num = 0f;
			rjwHealthCardUtility.highlight = true;
			bool flag = false;
			foreach (IGrouping<BodyPartRecord, Hediff> current in rjwHealthCardUtility.VisibleHediffGroupsInOrder(pawn, showBloodLoss))
			{
				flag = true;
				rjwHealthCardUtility.DrawHediffRow(rect2, pawn, current, ref num);
			}
			if (!flag)
			{
				Widgets.NoneLabelCenteredVertically(new Rect(0f, 0f, viewRect.width, outRect.height), "(" + "NoHealthConditions".Translate() + ")");
				num = outRect.height - 1f;
			}
			if (Event.current.type == EventType.Layout)
			{
				rjwHealthCardUtility.scrollViewHeight = num;
			}
			Widgets.EndScrollView();
			float bleedRateTotal = pawn.health.hediffSet.BleedRateTotal;
			if (bleedRateTotal > 0.01f)
			{
				Rect rect3 = new Rect(0f, rect.height - lineHeight, rect.width, lineHeight);
				string text = string.Concat(new string[]
				{
					"BleedingRate".Translate(),
					": ",
					bleedRateTotal.ToStringPercent(),
					"/",
					"LetterDay".Translate()
				});
				int num2 = HealthUtility.TicksUntilDeathDueToBloodLoss(pawn);
				if (num2 < 60000)
				{
					text = text + " (" + "TimeToDeath".Translate(num2.ToStringTicksToPeriod()) + ")";
				}
				else
				{
					text = text + " (" + "WontBleedOutSoon".Translate() + ")";
				}
				Widgets.Label(rect3, text);
			}
			GUI.EndGroup();
			GUI.color = Color.white;
		}

		[DebuggerHidden]
		public static IEnumerable<IGrouping<BodyPartRecord, Hediff>> VisibleHediffGroupsInOrder(Pawn pawn, bool showBloodLoss)
		{
			foreach (IGrouping<BodyPartRecord, Hediff> group in from x in rjwHealthCardUtility.VisibleHediffs(pawn, showBloodLoss)
			group x by x.Part into x
			orderby rjwHealthCardUtility.GetListPriority(x.First<Hediff>().Part) descending
			select x)
			{
				yield return group;
			}
		}

		public static float GetListPriority(BodyPartRecord rec)
		{
			if (rec == null)
			{
				return 9999999f;
			}
			return (float)((int)rec.height * 10000) + rec.coverageAbsWithChildren;
		}

		[DebuggerHidden]
		public static IEnumerable<Hediff> VisibleHediffs(Pawn pawn, bool showBloodLoss)
		{
			if (!rjwHealthCardUtility.showAllHediffs)
			{
				List<Hediff_MissingPart> mpca = pawn.health.hediffSet.GetMissingPartsCommonAncestors();
				for (int i = 0; i < mpca.Count; i++)
				{
					yield return mpca[i];
				}
				IEnumerable<Hediff> visibleDiffs = from d in pawn.health.hediffSet.hediffs
				where !(d is Hediff_MissingPart) && d.Visible && (showBloodLoss || d.def != HediffDefOf.BloodLoss)
				select d;
				foreach (Hediff diff in visibleDiffs)
				{
					yield return diff;
				}
			}
			else
			{
				foreach (Hediff diff2 in pawn.health.hediffSet.hediffs)
				{
					yield return diff2;
				}
			}
		}

		public static float DrawMedOperationsTab(Rect leftRect, Pawn pawn, Thing thingForMedBills, float curY)
		{
			curY += 2f;
			Func<List<FloatMenuOption>> recipeOptionsMaker = delegate
			{
				List<FloatMenuOption> list = new List<FloatMenuOption>();
				foreach (RecipeDef current in thingForMedBills.def.AllRecipes)
				{
					if (current.AvailableNow)
					{
						IEnumerable<ThingDef> enumerable = current.PotentiallyMissingIngredients(null, thingForMedBills.Map);
						if (!enumerable.Any((ThingDef x) => x.isTechHediff))
						{
							if (!enumerable.Any((ThingDef x) => x.IsDrug))
							{
								if (!enumerable.Any<ThingDef>() || !current.dontShowIfAnyIngredientMissing)
								{
									if (current.targetsBodyPart)
									{
										foreach (BodyPartRecord current2 in current.Worker.GetPartsToApplyOn(pawn, current))
										{
											list.Add(rjwHealthCardUtility.GenerateSurgeryOption(pawn, thingForMedBills, current, enumerable, current2));
										}
									}
									else
									{
										list.Add(rjwHealthCardUtility.GenerateSurgeryOption(pawn, thingForMedBills, current, enumerable, null));
									}
								}
							}
						}
					}
				}
				return list;
			};
			Rect rect = new Rect(leftRect.x - 9f, curY, leftRect.width, leftRect.height - curY - 20f);
			((IBillGiver)thingForMedBills).BillStack.DoListing(rect, recipeOptionsMaker, ref rjwHealthCardUtility.billsScrollPosition, ref rjwHealthCardUtility.billsScrollHeight);
			return curY;
		}

		public static FloatMenuOption GenerateSurgeryOption(Pawn pawn, Thing thingForMedBills, RecipeDef recipe, IEnumerable<ThingDef> missingIngredients, BodyPartRecord part = null)
		{
			string text = recipe.Worker.GetLabelWhenUsedOn(pawn, part).CapitalizeFirst();
			if (part != null && !recipe.hideBodyPartNames)
			{
				text = text + " (" + part.Label + ")";
			}
			FloatMenuOption floatMenuOption;
			if (missingIngredients.Any<ThingDef>())
			{
				text += " (";
				bool flag = true;
				foreach (ThingDef current in missingIngredients)
				{
					if (!flag)
					{
						text += ", ";
					}
					flag = false;
					text += "MissingMedicalBillIngredient".Translate(current.label);
				}
				text += ")";
				floatMenuOption = new FloatMenuOption(text, null, MenuOptionPriority.Default, null, null, 0f, null, null);
			}
			else
			{
				Action action = delegate
				{
					Pawn pawn2 = thingForMedBills as Pawn;
					if (pawn2 == null)
					{
						return;
					}
					Bill_Medical bill_Medical = new Bill_Medical(recipe);
					pawn2.BillStack.AddBill(bill_Medical);
					bill_Medical.Part = part;
					if (recipe.conceptLearned != null)
					{
						PlayerKnowledgeDatabase.KnowledgeDemonstrated(recipe.conceptLearned, KnowledgeAmount.Total);
					}
					Map map = thingForMedBills.Map;
					if (!map.mapPawns.FreeColonists.Any((Pawn col) => recipe.PawnSatisfiesSkillRequirements(col)))
					{
						Bill.CreateNoPawnsWithSkillDialog(recipe);
					}
					if (!pawn2.InBed() && pawn2.RaceProps.IsFlesh)
					{
						if (pawn2.RaceProps.Humanlike)
						{
							if (!map.listerBuildings.allBuildingsColonist.Any((Building x) => x is Building_Bed && RestUtility.CanUseBedEver(pawn, x.def) && ((Building_Bed)x).Medical))
							{
								Messages.Message("MessageNoMedicalBeds".Translate(), pawn2, MessageTypeDefOf.CautionInput, false);
							}
						}
						else if (!map.listerBuildings.allBuildingsColonist.Any((Building x) => x is Building_Bed && RestUtility.CanUseBedEver(pawn, x.def)))
						{
							Messages.Message("MessageNoAnimalBeds".Translate(), pawn2, MessageTypeDefOf.CautionInput, false);
						}
					}
					if (pawn2.Faction != null && !pawn2.Faction.def.hidden && !pawn2.Faction.HostileTo(Faction.OfPlayer) && recipe.Worker.IsViolationOnPawn(pawn2, part, Faction.OfPlayer))
					{
						Messages.Message("MessageMedicalOperationWillAngerFaction".Translate(pawn2.Faction), pawn2, MessageTypeDefOf.CautionInput, false);
					}
					ThingDef minRequiredMedicine = rjwHealthCardUtility.GetMinRequiredMedicine(recipe);
					if (minRequiredMedicine != null && pawn2.playerSettings != null && !pawn2.playerSettings.medCare.AllowsMedicine(minRequiredMedicine))
					{
						Messages.Message("MessageTooLowMedCare".Translate(minRequiredMedicine.label, pawn2.LabelShort, pawn2.playerSettings.medCare.GetLabel(), pawn2.Named("PAWN")), pawn2, MessageTypeDefOf.CautionInput, false);
					}
				};
				floatMenuOption = new FloatMenuOption(text, action, MenuOptionPriority.Default, null, null, 0f, null, null);
			}
			floatMenuOption.extraPartWidth = 29f;
			floatMenuOption.extraPartOnGUI = ((Rect rect) => Widgets.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2f, recipe));
			return floatMenuOption;
		}

		public static ThingDef GetMinRequiredMedicine(RecipeDef recipe)
		{
			rjwHealthCardUtility.tmpMedicineBestToWorst.Clear();
			List<ThingDef> allDefsListForReading = DefDatabase<ThingDef>.AllDefsListForReading;
			for (int i = 0; i < allDefsListForReading.Count; i++)
			{
				if (allDefsListForReading[i].IsMedicine)
				{
					rjwHealthCardUtility.tmpMedicineBestToWorst.Add(allDefsListForReading[i]);
				}
			}
			rjwHealthCardUtility.tmpMedicineBestToWorst.SortByDescending((ThingDef x) => x.GetStatValueAbstract(StatDefOf.MedicalPotency, null));
			ThingDef thingDef = null;
			for (int j = 0; j < recipe.ingredients.Count; j++)
			{
				ThingDef thingDef2 = null;
				for (int k = 0; k < rjwHealthCardUtility.tmpMedicineBestToWorst.Count; k++)
				{
					if (recipe.ingredients[j].filter.Allows(rjwHealthCardUtility.tmpMedicineBestToWorst[k]))
					{
						thingDef2 = rjwHealthCardUtility.tmpMedicineBestToWorst[k];
					}
				}
				if (thingDef2 != null && (thingDef == null || thingDef2.GetStatValueAbstract(StatDefOf.MedicalPotency, null) > thingDef.GetStatValueAbstract(StatDefOf.MedicalPotency, null)))
				{
					thingDef = thingDef2;
				}
			}
			rjwHealthCardUtility.tmpMedicineBestToWorst.Clear();
			return thingDef;
		}

		public static float DrawOverviewTab(Rect leftRect, Pawn pawn, float curY)
		{
			curY += 4f;
			Text.Font = GameFont.Tiny;
			Text.Anchor = TextAnchor.UpperLeft;
			GUI.color = new Color(0.9f, 0.9f, 0.9f);
			string text = string.Empty;
			if (pawn.gender != Gender.None)
			{
				text = pawn.GetGenderLabel() + " ";
			}
			text = text + pawn.def.label + ", " + "AgeIndicator".Translate(pawn.ageTracker.AgeNumberString);
			Rect rect = new Rect(0f, curY, leftRect.width, 34f);
			Widgets.Label(rect, text.CapitalizeFirst());
			TooltipHandler.TipRegion(rect, () => pawn.ageTracker.AgeTooltipString, 73412);
			if (Mouse.IsOver(rect))
			{
				Widgets.DrawHighlight(rect);
			}
			GUI.color = Color.white;
			curY += 34f;
			if (pawn.foodRestriction != null && pawn.foodRestriction.Configurable)
			{
				Rect rect2 = new Rect(0f, curY, leftRect.width * 0.42f, 23f);
				Text.Anchor = TextAnchor.MiddleLeft;
				Widgets.Label(rect2, "FoodRestriction".Translate());
				GenUI.ResetLabelAlign();
				Rect rect3 = new Rect(rect2.width, curY, leftRect.width - rect2.width, 23f);
				if (Widgets.ButtonText(rect3, pawn.foodRestriction.CurrentFoodRestriction.label, true, false, true))
				{
					List<FloatMenuOption> list = new List<FloatMenuOption>();
					List<FoodRestriction> allFoodRestrictions = Current.Game.foodRestrictionDatabase.AllFoodRestrictions;
					for (int i = 0; i < allFoodRestrictions.Count; i++)
					{
						FoodRestriction localRestriction = allFoodRestrictions[i];
						list.Add(new FloatMenuOption(localRestriction.label, delegate
						{
							pawn.foodRestriction.CurrentFoodRestriction = localRestriction;
						}, MenuOptionPriority.Default, null, null, 0f, null, null));
					}
					list.Add(new FloatMenuOption("ManageFoodRestrictions".Translate(), delegate
					{
						Find.WindowStack.Add(new Dialog_ManageFoodRestrictions(null));
					}, MenuOptionPriority.Default, null, null, 0f, null, null));
					Find.WindowStack.Add(new FloatMenu(list));
				}
				curY += 23f;
			}
			if (pawn.IsColonist && !pawn.Dead)
			{
				bool selfTend = pawn.playerSettings.selfTend;
				Rect rect4 = new Rect(0f, curY, leftRect.width, 24f);
				Widgets.CheckboxLabeled(rect4, "SelfTend".Translate(), ref pawn.playerSettings.selfTend, false, null, null, false);
				if (pawn.playerSettings.selfTend && !selfTend)
				{
					if (pawn.story.WorkTypeIsDisabled(WorkTypeDefOf.Doctor))
					{
						pawn.playerSettings.selfTend = false;
						Messages.Message("MessageCannotSelfTendEver".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.RejectInput, false);
					}
					else if (pawn.workSettings.GetPriority(WorkTypeDefOf.Doctor) == 0)
					{
						Messages.Message("MessageSelfTendUnsatisfied".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.CautionInput, false);
					}
				}
				TooltipHandler.TipRegion(rect4, "SelfTendTip".Translate(Faction.OfPlayer.def.pawnsPlural, 0.7f.ToStringPercent()).CapitalizeFirst());
				curY += 28f;
			}
			if (pawn.playerSettings != null && !pawn.Dead && Current.ProgramState == ProgramState.Playing)
			{
				Rect rect5 = new Rect(0f, curY, 140f, 28f);
				MedicalCareUtility.MedicalCareSetter(rect5, ref pawn.playerSettings.medCare);
				if (Widgets.ButtonText(new Rect(leftRect.width - 70f, curY, 70f, 28f), "MedGroupDefaults".Translate(), true, false, true))
				{
					Find.WindowStack.Add(new Dialog_MedicalDefaults());
				}
				curY += 32f;
			}
			Text.Font = GameFont.Small;
			if (pawn.def.race.IsFlesh)
			{
				Pair<string, Color> painLabel = rjwHealthCardUtility.GetPainLabel(pawn);
				string painTip = rjwHealthCardUtility.GetPainTip(pawn);
				curY = rjwHealthCardUtility.DrawLeftRow(leftRect, curY, "PainLevel".Translate(), painLabel.First, painLabel.Second, painTip);
			}
			if (!pawn.Dead)
			{
				IEnumerable<PawnCapacityDef> source;
				if (pawn.def.race.Humanlike)
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnHumanlikes
					select x;
				}
				else if (pawn.def.race.Animal)
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnAnimals
					select x;
				}
				else
				{
					source = from x in DefDatabase<PawnCapacityDef>.AllDefs
					where x.showOnMechanoids
					select x;
				}
				foreach (PawnCapacityDef current in from act in source
				orderby act.listOrder
				select act)
				{
					if (PawnCapacityUtility.BodyCanEverDoCapacity(pawn.RaceProps.body, current))
					{
						PawnCapacityDef activityLocal = current;
						Pair<string, Color> efficiencyLabel = rjwHealthCardUtility.GetEfficiencyLabel(pawn, current);
						Func<string> textGetter = () => (!pawn.Dead) ? rjwHealthCardUtility.GetPawnCapacityTip(pawn, activityLocal) : string.Empty;
						curY = rjwHealthCardUtility.DrawLeftRow(leftRect, curY, current.GetLabelFor(pawn.RaceProps.IsFlesh, pawn.RaceProps.Humanlike).CapitalizeFirst(), efficiencyLabel.First, efficiencyLabel.Second, new TipSignal(textGetter, pawn.thingIDNumber ^ (int)current.index));
					}
				}
			}
			return curY;
		}

		public static float DrawLeftRow(Rect leftRect, float curY, string leftLabel, string rightLabel, Color rightLabelColor, TipSignal tipSignal)
		{
			Rect rect = new Rect(0f, curY, leftRect.width, 20f);
			if (Mouse.IsOver(rect))
			{
				GUI.color = rjwHealthCardUtility.HighlightColor;
				GUI.DrawTexture(rect, TexUI.HighlightTex);
			}
			GUI.color = Color.white;
			Widgets.Label(new Rect(0f, curY, leftRect.width * 0.65f, 30f), leftLabel);
			GUI.color = rightLabelColor;
			Widgets.Label(new Rect(leftRect.width * 0.65f, curY, leftRect.width * 0.35f, 30f), rightLabel);
			TooltipHandler.TipRegion(new Rect(0f, curY, leftRect.width, 20f), tipSignal);
			curY += 20f;
			return curY;
		}

		public static void DrawHediffRow(Rect rect, Pawn pawn, IEnumerable<Hediff> diffs, ref float curY)
		{
			float num = rect.width * 0.375f;
			float width = rect.width - num - 20f;
			BodyPartRecord part = diffs.First<Hediff>().Part;
			float a;
			if (part == null)
			{
				a = Text.CalcHeight("WholeBody".Translate(), num);
			}
			else
			{
				a = Text.CalcHeight(part.LabelCap, num);
			}
			float b = 0f;
			float num2 = curY;
			float num3 = 0f;
			foreach (IGrouping<int, Hediff> current in from x in diffs
			group x by x.UIGroupKey)
			{
				int num4 = current.Count<Hediff>();
				string text = current.First<Hediff>().LabelCap;
				if (num4 != 1)
				{
					text = text + " x" + num4.ToString();
				}
				num3 += Text.CalcHeight(text, width);
			}
			b = num3;
			Rect rect2 = new Rect(0f, curY, rect.width, Mathf.Max(a, b));
			rjwHealthCardUtility.DoRightRowHighlight(rect2);
			if (part != null)
			{
				GUI.color = HealthUtility.GetPartConditionLabel(pawn, part).Second;
				Widgets.Label(new Rect(0f, curY, num, 100f), part.LabelCap);
			}
			else
			{
				GUI.color = HealthUtility.DarkRedColor;
				Widgets.Label(new Rect(0f, curY, num, 100f), "WholeBody".Translate());
			}
			GUI.color = Color.white;
			foreach (IGrouping<int, Hediff> current2 in from x in diffs
			group x by x.UIGroupKey)
			{
				int num5 = 0;
				Hediff hediff = null;
				Texture2D texture2D = null;
				TextureAndColor textureAndColor = null;
				float num6 = 0f;
				foreach (Hediff current3 in current2)
				{
					if (num5 == 0)
					{
						hediff = current3;
					}
					textureAndColor = current3.StateIcon;
					if (current3.Bleeding)
					{
						texture2D = rjwHealthCardUtility.BleedingIcon;
					}
					num6 += current3.BleedRate;
					num5++;
				}
				string text2 = hediff.LabelCap;
				if (num5 != 1)
				{
					text2 = text2 + " x" + num5.ToStringCached();
				}
				GUI.color = hediff.LabelColor;
				float num7 = Text.CalcHeight(text2, width);
				Rect rect3 = new Rect(num, curY, width, num7);
				Widgets.Label(rect3, text2);
				GUI.color = Color.white;
				Rect rect4 = new Rect(rect2.xMax - 20f, curY, 20f, 20f);
				if (texture2D)
				{
					Rect position = rect4.ContractedBy(GenMath.LerpDouble(0f, 0.6f, 5f, 0f, Mathf.Min(num6, 1f)));
					GUI.DrawTexture(position, texture2D);
					rect4.x -= rect4.width;
				}
				if (textureAndColor.HasValue)
				{
					GUI.color = textureAndColor.Color;
					GUI.DrawTexture(rect4, textureAndColor.Texture);
					GUI.color = Color.white;
					rect4.x -= rect4.width;
				}
				curY += num7;
			}
			GUI.color = Color.white;
			curY = num2 + Mathf.Max(a, b);
			if (Widgets.ButtonInvisible(rect2, false))
			{
				rjwHealthCardUtility.EntryClicked(diffs, pawn);
			}
			TooltipHandler.TipRegion(rect2, new TipSignal(() => rjwHealthCardUtility.GetTooltip(diffs, pawn, part), (int)curY + 7857));
		}

		public static string GetPainTip(Pawn pawn)
		{
			return "PainLevel".Translate() + ": " + (pawn.health.hediffSet.PainTotal * 100f).ToString("F0") + "%";
		}

		public static string GetPawnCapacityTip(Pawn pawn, PawnCapacityDef capacity)
		{
			List<PawnCapacityUtility.CapacityImpactor> list = new List<PawnCapacityUtility.CapacityImpactor>();
			float num = PawnCapacityUtility.CalculateCapacityLevel(pawn.health.hediffSet, capacity, list);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(capacity.LabelCap + ": " + (num * 100f).ToString("F0") + "%");
			if (list.Count > 0)
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("AffectedBy".Translate());
				for (int i = 0; i < list.Count; i++)
				{
					if (list[i] is PawnCapacityUtility.CapacityImpactorHediff)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[i].Readable(pawn)));
					}
				}
				for (int j = 0; j < list.Count; j++)
				{
					if (list[j] is PawnCapacityUtility.CapacityImpactorBodyPartHealth)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[j].Readable(pawn)));
					}
				}
				for (int k = 0; k < list.Count; k++)
				{
					if (list[k] is PawnCapacityUtility.CapacityImpactorCapacity)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[k].Readable(pawn)));
					}
				}
				for (int l = 0; l < list.Count; l++)
				{
					if (list[l] is PawnCapacityUtility.CapacityImpactorPain)
					{
						stringBuilder.AppendLine(string.Format("  {0}", list[l].Readable(pawn)));
					}
				}
			}
			return stringBuilder.ToString();
		}

		public static string GetTooltip(IEnumerable<Hediff> diffs, Pawn pawn, BodyPartRecord part)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (part != null)
			{
				stringBuilder.Append(part.LabelCap + ": ");
				stringBuilder.AppendLine(" " + pawn.health.hediffSet.GetPartHealth(part).ToString() + " / " + part.def.GetMaxHealth(pawn).ToString());
				float num = PawnCapacityUtility.CalculatePartEfficiency(pawn.health.hediffSet, part, false, null);
				if (num != 1f)
				{
					stringBuilder.AppendLine("Efficiency".Translate() + ": " + num.ToStringPercent());
				}
			}
			else
			{
				stringBuilder.AppendLine("WholeBody".Translate());
			}
			stringBuilder.AppendLine("------------------");
			foreach (IGrouping<int, Hediff> current in from x in diffs
			group x by x.UIGroupKey)
			{
				foreach (Hediff current2 in current)
				{
					string severityLabel = current2.SeverityLabel;
					bool flag = rjwHealthCardUtility.showHediffsDebugInfo && !current2.DebugString().NullOrEmpty();
					if (!current2.Label.NullOrEmpty() || !severityLabel.NullOrEmpty() || !current2.CapMods.NullOrEmpty<PawnCapacityModifier>() || flag)
					{
						stringBuilder.Append(current2.LabelCap);
						if (!severityLabel.NullOrEmpty())
						{
							stringBuilder.Append(": " + severityLabel);
						}
						stringBuilder.AppendLine();
						string tipStringExtra = current2.TipStringExtra;
						if (!tipStringExtra.NullOrEmpty())
						{
							stringBuilder.AppendLine(tipStringExtra.TrimEndNewlines().Indented("    "));
						}
						if (flag)
						{
							stringBuilder.AppendLine(current2.DebugString().TrimEndNewlines());
						}
					}
				}
			}
			string s;
			LogEntry logEntry;
			if (rjwHealthCardUtility.GetCombatLogInfo(diffs, out s, out logEntry))
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine("Cause:");
				stringBuilder.AppendLine(s.Indented("    "));
			}
			return stringBuilder.ToString().TrimEnd(new char[0]);
		}

		public static void EntryClicked(IEnumerable<Hediff> diffs, Pawn pawn)
		{
			LogEntry combatLogEntry;
			string text;
			if (!rjwHealthCardUtility.GetCombatLogInfo(diffs, out text, out combatLogEntry) || combatLogEntry == null)
			{
				return;
			}
			if (!Find.BattleLog.Battles.Any((Battle b) => b.Concerns(pawn) && b.Entries.Any((LogEntry e) => e == combatLogEntry)))
			{
				return;
			}
			ITab_Pawn_Log tab_Pawn_Log = InspectPaneUtility.OpenTab(typeof(ITab_Pawn_Log)) as ITab_Pawn_Log;
			if (tab_Pawn_Log == null)
			{
				return;
			}
			tab_Pawn_Log.SeekTo(combatLogEntry);
			tab_Pawn_Log.Highlight(combatLogEntry);
		}

		public static bool GetCombatLogInfo(IEnumerable<Hediff> diffs, out string combatLogText, out LogEntry combatLogEntry)
		{
			combatLogText = null;
			combatLogEntry = null;
			foreach (Hediff current in diffs)
			{
				if ((current.combatLogEntry != null && current.combatLogEntry.Target != null) || (combatLogText.NullOrEmpty() && !current.combatLogText.NullOrEmpty()))
				{
					combatLogEntry = ((current.combatLogEntry == null) ? null : current.combatLogEntry.Target);
					combatLogText = current.combatLogText;
				}
				if (combatLogEntry != null)
				{
					return true;
				}
			}
			return false;
		}

		public static void DoRightRowHighlight(Rect rowRect)
		{
			if (rjwHealthCardUtility.highlight)
			{
				GUI.color = rjwHealthCardUtility.StaticHighlightColor;
				GUI.DrawTexture(rowRect, TexUI.HighlightTex);
			}
			rjwHealthCardUtility.highlight = !rjwHealthCardUtility.highlight;
			if (Mouse.IsOver(rowRect))
			{
				GUI.color = rjwHealthCardUtility.HighlightColor;
				GUI.DrawTexture(rowRect, TexUI.HighlightTex);
			}
		}

		public static void DoDebugOptions(Rect rightRect, Pawn pawn)
		{
			Widgets.CheckboxLabeled(new Rect(rightRect.x, rightRect.y - 25f, 110f, 30f), "Dev: AllDiffs", ref rjwHealthCardUtility.showAllHediffs, false, null, null, false);
			Widgets.CheckboxLabeled(new Rect(rightRect.x + 115f, rightRect.y - 25f, 120f, 30f), "DiffsDebugInfo", ref rjwHealthCardUtility.showHediffsDebugInfo, false, null, null, false);
			if (Widgets.ButtonText(new Rect(rightRect.x + 240f, rightRect.y - 27f, 115f, 25f), "Debug info", true, false, true))
			{
				List<FloatMenuOption> list = new List<FloatMenuOption>();
				list.Add(new FloatMenuOption("Parts hit chance (this part or any child node)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby x.coverageAbsWithChildren descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.coverageAbsWithChildren.ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("Parts hit chance (exactly this part)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					float num = 0f;
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby x.coverageAbs descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.coverageAbs.ToStringPercent());
						num += current.coverageAbs;
					}
					stringBuilder.AppendLine();
					stringBuilder.AppendLine("Total " + num.ToStringPercent());
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("Per-part efficiency", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.RaceProps.body.AllParts)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + PawnCapacityUtility.CalculatePartEfficiency(pawn.health.hediffSet, current, false, null).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("BodyPartGroup efficiency (of only natural parts)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartGroupDef current in from x in DefDatabase<BodyPartGroupDef>.AllDefs
					where pawn.RaceProps.body.AllParts.Any((BodyPartRecord y) => y.groups.Contains(x))
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + " " + PawnCapacityUtility.CalculateNaturalPartsAverageEfficiency(pawn.health.hediffSet, current).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("IsSolid", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.def.IsSolid(current, pawn.health.hediffSet.hediffs));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("IsSkinCovered", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + current.def.IsSkinCovered(current, pawn.health.hediffSet));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("does have added parts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap + " " + pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(current));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("GetNotMissingParts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null))
					{
						stringBuilder.AppendLine(current.LabelCap);
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("GetCoverageOfNotMissingNaturalParts", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby pawn.health.hediffSet.GetCoverageOfNotMissingNaturalParts(x) descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + ": " + pawn.health.hediffSet.GetCoverageOfNotMissingNaturalParts(current).ToStringPercent());
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("parts nutrition (assuming adult)", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					float totalCorpseNutrition = StatDefOf.Nutrition.Worker.GetValueAbstract(pawn.RaceProps.corpseDef, null);
					foreach (BodyPartRecord current in from x in pawn.RaceProps.body.AllParts
					orderby FoodUtility.GetBodyPartNutrition(totalCorpseNutrition, pawn, x) descending
					select x)
					{
						stringBuilder.AppendLine(current.LabelCap + ": " + FoodUtility.GetBodyPartNutrition(totalCorpseNutrition, pawn, current));
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("test permanent injury pain factor probability", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					float num4 = 0f;
					int num5 = 10000;
					for (int i = 0; i < num5; i++)
					{
						float num6 = Mathf.Max(0f, Rand.ByCurve(HealthTuning.PermanentInjuryPainFactorRandomCurve));
						if (num6 < 0f)
						{
							Log.Error("Pain factor < 0", false);
						}
						if (num6 == 0f)
						{
							num++;
						}
						if (num6 < 1f)
						{
							num2++;
						}
						if (num6 < 5f)
						{
							num3++;
						}
						if (num6 > num4)
						{
							num4 = num6;
						}
					}
					stringBuilder.AppendLine("total: " + num5);
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"0: ",
						num,
						" (",
						((float)num / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"< 1: ",
						num2,
						" (",
						((float)num2 / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine(string.Concat(new object[]
					{
						"< 5: ",
						num3,
						" (",
						((float)num3 / (float)num5).ToStringPercent(),
						")"
					}));
					stringBuilder.AppendLine("max: " + num4);
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("HediffGiver_Birthday chance at age", delegate
				{
					List<FloatMenuOption> list2 = new List<FloatMenuOption>();
					foreach (HediffGiverSetDef current in pawn.RaceProps.hediffGiverSets)
					{
						foreach (HediffGiver_Birthday current2 in current.hediffGivers.OfType<HediffGiver_Birthday>())
						{
							HediffGiver_Birthday hLocal = current2;
							FloatMenuOption item = new FloatMenuOption(current.defName + " - " + current2.hediff.defName, delegate
							{
								StringBuilder stringBuilder = new StringBuilder();
								stringBuilder.AppendLine("% of pawns which will have at least 1 " + hLocal.hediff.label + " at age X:");
								stringBuilder.AppendLine();
								int num = 1;
								while ((float)num < pawn.RaceProps.lifeExpectancy + 20f)
								{
									stringBuilder.AppendLine(num + ": " + hLocal.DebugChanceToHaveAtAge(pawn, num).ToStringPercent());
									num++;
								}
								Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
							}, MenuOptionPriority.Default, null, null, 0f, null, null);
							list2.Add(item);
						}
					}
					Find.WindowStack.Add(new FloatMenu(list2));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				list.Add(new FloatMenuOption("HediffGiver_Birthday count at age", delegate
				{
					StringBuilder stringBuilder = new StringBuilder();
					stringBuilder.AppendLine("Average hediffs count (from HediffGiver_Birthday) at age X:");
					stringBuilder.AppendLine();
					int num = 1;
					while ((float)num < pawn.RaceProps.lifeExpectancy + 20f)
					{
						float num2 = 0f;
						foreach (HediffGiverSetDef current in pawn.RaceProps.hediffGiverSets)
						{
							foreach (HediffGiver_Birthday current2 in current.hediffGivers.OfType<HediffGiver_Birthday>())
							{
								num2 += current2.DebugChanceToHaveAtAge(pawn, num);
							}
						}
						stringBuilder.AppendLine(num + ": " + num2.ToStringDecimalIfSmall());
						num++;
					}
					Find.WindowStack.Add(new Dialog_MessageBox(stringBuilder.ToString(), null, null, null, null, null, false, null, null));
				}, MenuOptionPriority.Default, null, null, 0f, null, null));
				Find.WindowStack.Add(new FloatMenu(list));
			}
		}

		public static Pair<string, Color> GetEfficiencyLabel(Pawn pawn, PawnCapacityDef activity)
		{
			float level = pawn.health.capacities.GetLevel(activity);
			string first = string.Empty;
			Color second = Color.white;
			if (level <= 0f)
			{
				first = "None".Translate();
				second = HealthUtility.DarkRedColor;
			}
			else if (level < 0.4f)
			{
				first = "VeryPoor".Translate();
				second = rjwHealthCardUtility.VeryPoorColor;
			}
			else if (level < 0.7f)
			{
				first = "Poor".Translate();
				second = rjwHealthCardUtility.PoorColor;
			}
			else if (level < 1f && !Mathf.Approximately(level, 1f))
			{
				first = "Weakened".Translate();
				second = rjwHealthCardUtility.WeakenedColor;
			}
			else if (Mathf.Approximately(level, 1f))
			{
				first = "GoodCondition".Translate();
				second = HealthUtility.GoodConditionColor;
			}
			else
			{
				first = "Enhanced".Translate();
				second = rjwHealthCardUtility.EnhancedColor;
			}
			return new Pair<string, Color>(first, second);
		}

		public static Pair<string, Color> GetPainLabel(Pawn pawn)
		{
			float painTotal = pawn.health.hediffSet.PainTotal;
			string first = string.Empty;
			Color second = Color.white;
			if (Mathf.Approximately(painTotal, 0f))
			{
				first = "NoPain".Translate();
				second = HealthUtility.GoodConditionColor;
			}
			else if (painTotal < 0.15f)
			{
				first = "LittlePain".Translate();
				second = Color.gray;
			}
			else if (painTotal < 0.4f)
			{
				first = "MediumPain".Translate();
				second = rjwHealthCardUtility.MediumPainColor;
			}
			else if (painTotal < 0.8f)
			{
				first = "SeverePain".Translate();
				second = rjwHealthCardUtility.SeverePainColor;
			}
			else
			{
				first = "ExtremePain".Translate();
				second = HealthUtility.DarkRedColor;
			}
			return new Pair<string, Color>(first, second);
		}
	}
}


code:
using System.Collections.Generic;
using Verse;
using RimWorld.Planet;

namespace rjw
{
	/// <summary>
	/// Hugslib Utility Data object storing the RJW info
	/// also implements extensions to Pawn method
	/// is used as a static field in PawnData
	/// </summary>
	public class DataStore : WorldComponent
	{
		public DataStore(World world) : base(world)
		{
		}

		public Dictionary<int, PawnData> PawnData = new Dictionary<int, PawnData> ();
		//public Dictionary<int, PartsData> PartsData = new Dictionary<int, PartsData> ();

		public override void ExposeData()
		{
			if (Scribe.mode==LoadSaveMode.Saving)
				PawnData.RemoveAll(item => item.Value==null || !item.Value.IsValid);
			base.ExposeData();
			Scribe_Collections.Look(ref PawnData, "Data", LookMode.Value, LookMode.Deep);
			if (Scribe.mode == LoadSaveMode.LoadingVars)
			{
				if (PawnData == null) PawnData = new Dictionary<int, PawnData>();
			}
		}

		public PawnData GetPawnData(Pawn pawn)
		{
			PawnData res;
			//--Log.Message("Getting data for " + pawn);
			//--Log.Message("Pawn " + pawn + " id " + pawn.thingIDNumber);
			//--Log.Message("PawnData isn't null " + !(PawnData == null));
			var filled = PawnData.TryGetValue(pawn.thingIDNumber, out res);
			//--Log.Message("Output is not null" + PawnData.TryGetValue(pawn.thingIDNumber, out res));
			//--Log.Message("Out is not null " + (res != null));
			//--Log.Message("Out is valid " + (res != null && res.IsValid));
			if ((res==null) || (!res.IsValid))
			{
				if (filled)
				{
					//--Log.Message("Clearing incorrect data for " + pawn);
					PawnData.Remove(pawn.thingIDNumber);
				}
				//--Log.Message("PawnData missing, creating for " + pawn);
				res = new PawnData(pawn);
				PawnData.Add(pawn.thingIDNumber, res);
			}
			//--Log.Message("Finishing");
			//--Log.Message("PawnData is " + res.Comfort + " " + res.Service + " " + res.Breeding);
			return res;
		}

		void SetPawnData(Pawn pawn, PawnData data)
		{
			PawnData.Add(pawn.thingIDNumber, data);
		}
	}
}


code:
using Verse;
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using RimWorld.Planet;

namespace rjw
{
	/// <summary>
	/// Collection of pawn designators lists
	/// </summary>
	public class DesignatorsData : WorldComponent
	{
		public DesignatorsData(World world) : base(world)
		{
		}

		public static List<Pawn> rjwHero = new List<Pawn>();
		public static List<Pawn> rjwComfort = new List<Pawn>();
		public static List<Pawn> rjwService = new List<Pawn>();
		public static List<Pawn> rjwMilking = new List<Pawn>();
		public static List<Pawn> rjwBreeding = new List<Pawn>();
		public static List<Pawn> rjwBreedingAnimal = new List<Pawn>();

		//public static Dictionary<string, List<Pawn>> Designators = new Dictionary<string, List<Pawn>>();

		/// <summary>
		/// update designators on game load
		/// </summary>
		public void Update()
		{
			//if (RJWSettings.DevMode)
				//ModLog.Message("DesignatorsData::Update()");
			rjwHero = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedHero()).ToList();
			rjwComfort = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedComfort()).ToList();
			rjwService = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedService()).ToList();
			rjwMilking = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedMilking()).ToList();
			rjwBreeding = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreeding()).ToList();
			rjwBreedingAnimal = PawnsFinder.All_AliveOrDead.Where(p => p.IsDesignatedBreedingAnimal()).ToList();
			//ModLog.Message("rjwHero "+rjwHero.Count());
			//ModLog.Message("rjwComfort "+rjwComfort.Count());
			//ModLog.Message("rjwService "+rjwService.Count());
			//ModLog.Message("rjwMilking "+rjwMilking.Count());
			//ModLog.Message("rjwBreeding "+rjwBreeding.Count());
			//ModLog.Message("rjwBreedingAnimal "+rjwBreedingAnimal.Count());

			//Designators = new Dictionary<string, List<Pawn>>();
			//Designators.Add("rjwHero", rjwHero);
			//Designators.Add("rjwComfort", rjwComfort);
			//Designators.Add("rjwService", rjwService);
			//Designators.Add("rjwMilking", rjwMilking);
			//Designators.Add("rjwBreeding", rjwBreeding);
			//Designators.Add("rjwBreedingAnimal", rjwBreedingAnimal);
		}
	}
}


code:
using HugsLib;
using RimWorld;
using Verse;

namespace rjw
{
	/// <summary>
	/// Rjw settings store
	/// </summary>
	public class SaveStorage : ModBase
	{
		public override string ModIdentifier => ModId;
		public static string ModId => "RJW";

		public static DataStore DataStore;//reference to savegame data, hopefully
		public static DesignatorsData DesignatorsData;//reference to savegame data, hopefully

		public override void SettingsChanged()
		{
			ToggleTabIfNeeded();
		}

		public override void WorldLoaded()
		{
			DataStore = Find.World.GetComponent<DataStore>();
			DesignatorsData = Find.World.GetComponent<DesignatorsData>();
			DesignatorsData.Update();
			ToggleTabIfNeeded();
			FixRjwHediffsOnlLoad();
		}
		protected override bool HarmonyAutoPatch { get => false; }//first.cs creates harmony and does some convoulted stuff with it

		private void ToggleTabIfNeeded()
		{
			DefDatabase<MainButtonDef>.GetNamed("Brothel").buttonVisible = RJWSettings.whoringtab_enabled;
		}
		private void FixRjwHediffsOnlLoad()
		{
			foreach (var pawn in PawnsFinder.All_AliveOrDead)
			{
				foreach (var hd in pawn.health.hediffSet.hediffs)
				{
					if (hd is Hediff_PartBaseNatural || hd is Hediff_PartBaseArtifical)
					{
						hd.TryGetComp<CompHediffBodyPart>().updatepartposition();
					}
				}
			}
		}
	}
}


code:
using System.Collections.Generic;
using Verse;
using System;
using System.ComponentModel;
using System.Linq;
using Verse.Noise;

namespace rjw
{
	/// <summary>
	/// Data about part sizes that is not tied to an individual hediffdef.
	/// </summary>
	public class PartStagesDef : Def
	{
		public float bandSizeBase;
		public float bandSizeInterval;
		public float cupSizeInterval;
		public List<string> cupSizeLabels;

		static readonly Lazy<PartStagesDef> instance = new Lazy<PartStagesDef>(() => DefDatabase<PartStagesDef>.AllDefs.Single());

		public static PartStagesDef Instance
		{
			get
			{
				return instance.Value;
			}
		}

		public static string GetCupSizeLabel(float size)
		{
			var i = Math.Max(0, Math.Min(Instance.cupSizeLabels.Count - 1, (int)size));
			return Instance.cupSizeLabels[i];
		}
	}
}


code:
using System;
using Verse;
using System.Linq;

namespace rjw
{
	/// <summary>
	/// Utility data object and a collection of extension methods for Pawn
	/// </summary>
	public class PawnData : IExposable
	{
		public Pawn Pawn = null;
		public bool Comfort = false;
		public bool Service = false;
		public bool Breeding = false;
		public bool Milking = false;
		public bool Hero = false;
		public bool Ironman = false;
		public string HeroOwner = "";
		public bool BreedingAnimal = false;
		public bool CanChangeDesignationColonist = false;
		public bool CanChangeDesignationPrisoner = false;
		public bool CanDesignateService = false;
		public bool CanDesignateMilking = false;
		public bool CanDesignateComfort = false;
		public bool CanDesignateBreedingAnimal = false;
		public bool CanDesignateBreeding = false;
		public bool CanDesignateHero = false;
		public bool ShowRMB_Menu = false;

		public bool isSlime = false;
		public bool isDemon = false;
		public bool oviPregnancy = false;

		public float raceSexDrive = 1.0f;

		public PawnData() { }

		public PawnData(Pawn pawn)
		{
			//Log.Message("Creating pawndata for " + pawn);
			Pawn = pawn;
			//Log.Message("This data is valid " + this.IsValid);

			if (RaceGroupDef_Helper.TryGetRaceGroupDef(Pawn, out var raceGroupDef))
			{
				oviPregnancy = raceGroupDef.oviPregnancy;
				raceSexDrive = raceGroupDef.raceSexDrive;
			}

			isDemon = Pawn.Has(RaceTag.Demon);
			isSlime = Pawn.Has(RaceTag.Slime);
			//Log.Warning("PawnData:: Pawn:" + xxx.get_pawnname(pawn));
			//Log.Warning("PawnData:: isSlime:" + isSlime);
			//Log.Warning("PawnData:: isDemon:" + isDemon);
			//Log.Warning("PawnData:: oviPregnancy:" + oviPregnancy);
		}

		public void ExposeData()
		{
			Scribe_References.Look(ref Pawn, "Pawn");
			Scribe_Values.Look(ref Comfort, "Comfort", false, true);
			Scribe_Values.Look(ref Service, "Service", false, true);
			Scribe_Values.Look(ref Breeding, "Breeding", false, true);
			Scribe_Values.Look(ref Milking, "Milking", false, true);
			Scribe_Values.Look(ref Hero, "Hero", false, true);
			Scribe_Values.Look(ref Ironman, "Ironman", false, true);
			Scribe_Values.Look(ref HeroOwner, "HeroOwner", "", true);
			Scribe_Values.Look(ref BreedingAnimal, "BreedingAnimal", false, true);
			Scribe_Values.Look(ref CanChangeDesignationColonist, "CanChangeDesignationColonist", false, true);
			Scribe_Values.Look(ref CanChangeDesignationPrisoner, "CanChangeDesignationPrisoner", false, true);
			Scribe_Values.Look(ref CanDesignateService, "CanDesignateService", false, true);
			Scribe_Values.Look(ref CanDesignateMilking, "CanDesignateMilking", false, true);
			Scribe_Values.Look(ref CanDesignateComfort, "CanDesignateComfort", false, true);
			Scribe_Values.Look(ref CanDesignateBreedingAnimal, "CanDesignateBreedingAnimal", false, true);
			Scribe_Values.Look(ref CanDesignateBreeding, "CanDesignateBreeding", false, true);
			Scribe_Values.Look(ref CanDesignateHero, "CanDesignateHero", false, true);
			Scribe_Values.Look(ref ShowRMB_Menu, "ShowRMB_Menu", false, true);
			Scribe_Values.Look(ref isSlime, "isSlime", false, true);
			Scribe_Values.Look(ref isDemon, "isDemon", false, true);
			Scribe_Values.Look(ref oviPregnancy, "oviPregnancy", false, true);
			Scribe_Values.Look(ref raceSexDrive, "raceSexDrive", 1.0f, true);
	}

	public bool IsValid { get { return Pawn != null; } }
	}
}


code:
using System.Collections.Generic;
using Verse;
using System;

namespace rjw
{
	/// <summary>
	/// Defines all RJW configuration related to a specific race or group of races.
	/// Core races should have RaceGroupDefs in RJW.
	/// Non-core races should have RaceGroupDefs in the separate RJWRaceSupport mod.
	/// Technically any mod could add a RaceGroupDef for its own races but we expect that to be rare.
	/// </summary>
	class RaceGroupDef : Def
	{
		public List<string> raceNames = null;
		public List<string> pawnKindNames = null;
		public List<string> anuses = null;
		public List<float> chanceanuses = null;
		public List<string> femaleBreasts = null;
		public List<float> chancefemaleBreasts = null;
		public List<string> femaleGenitals = null;
		public List<float> chancefemaleGenitals = null;
		public List<string> maleBreasts = null;
		public List<float> chancemaleBreasts = null;
		public List<string> maleGenitals = null;
		public List<float> chancemaleGenitals = null;

		public List<string> hybridRaceParents = null;
		public List<string> hybridChildKindDef = null;

		public List<string> tags = null;
		public bool hasSingleGender = false;
		public bool hasSexNeed = true;
		public bool hasFertility = true;
		public bool hasPregnancy = true;
		public bool oviPregnancy = false;
		public bool ImplantEggs = false;
		[Obsolete("isDemon is obsolete, use tags instead.")]
		public bool isDemon = false;
		[Obsolete("isSlime is obsolete, use tags instead.")]
		public bool isSlime = false;
		public float raceSexDrive = 1.0f;

		public string eggFertilizedDef = "RJW_EggFertilized";
		public string eggUnfertilizedDef = "RJW_EggUnfertilized";
		public float eggProgressUnfertilizedMax = 1.0f;
		public float eggLayIntervalDays = 3.5f;

		public List<string> GetRacePartDefNames(SexPartType sexPartType)
		{
			return sexPartType switch
			{
				SexPartType.Anus => anuses,
				SexPartType.FemaleBreast => femaleBreasts,
				SexPartType.FemaleGenital => femaleGenitals,
				SexPartType.MaleBreast => maleBreasts,
				SexPartType.MaleGenital => maleGenitals,
				_ => throw new ApplicationException($"Unrecognized sexPartType: {sexPartType}"),
			};
		}

		public List<float> GetChances(SexPartType sexPartType)
		{
			return sexPartType switch
			{
				SexPartType.Anus => chanceanuses,
				SexPartType.FemaleBreast => chancefemaleBreasts,
				SexPartType.FemaleGenital => chancefemaleGenitals,
				SexPartType.MaleBreast => chancemaleBreasts,
				SexPartType.MaleGenital => chancemaleGenitals,
				_ => throw new ApplicationException($"Unrecognized sexPartType: {sexPartType}"),
			};
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;

namespace rjw
{
	/// <summary>
	/// Defines how to create a single sex part on a newly created pawn.
	/// </summary>
	public class RacePartDef : Def
	{
		public bool IsNone => string.IsNullOrEmpty(hediffName);
		public static readonly RacePartDef None = new RacePartDef();

		/// <summary>
		/// The name of the hediff to create.
		/// Doesn't use the hediff directly because that causes issues when another mod wants to
		/// create and reference custom parts inheriting from rjw base defs.
		/// </summary>
		public string hediffName;
		public string fluidType;
		public float? fluidModifier;
		public SimpleCurve severityCurve;

		public bool TryGetHediffDef(out HediffDef hediffDef)
		{
			hediffDef = DefDatabase<HediffDef>.GetNamedSilentFail(hediffName);
			if (hediffDef == null)
			{
				ModLog.Error($"Could not find a HediffDef named {hediffName} referenced by RacePartDef named {defName}.");
				return false;
			}
			else
			{
				return true;
			}
		}
	}
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RimWorld;
using Verse;

namespace rjw
{
	public class RaceTag
	{
		// I only created tags for RaceGroupDef properties that seemed like keywords (like slime) rather than behavior (like oviPregnancy).
		public readonly static RaceTag Chitin = new RaceTag("Chitin");
		public readonly static RaceTag Demon = new RaceTag("Demon");
		public readonly static RaceTag Feathers = new RaceTag("Feathers");
		public readonly static RaceTag Fur = new RaceTag("Fur");
		public readonly static RaceTag Plant = new RaceTag("Plant");
		public readonly static RaceTag Robot = new RaceTag("Robot");
		public readonly static RaceTag Scales = new RaceTag("Scales");
		public readonly static RaceTag Skin = new RaceTag("Skin");
		public readonly static RaceTag Slime = new RaceTag("Slime");

		public string Key { get; }

		RaceTag(string key)
		{
			Key = key;
		}

		/// <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;
			}
		}
	}
}


code:
using System.Collections.Generic;
using Verse;

namespace rjw
{
	/// <summary>
	/// Just a simplest form of passing data from xml to the code
	/// </summary>
	class StringListDef : Def
	{
		public List<string> strings = new List<string>();
	}
}