preparing for rimworld 1.4

This commit is contained in:
c0ffee 2022-10-05 13:50:02 -07:00
parent 41608bde79
commit eb8817c75c
93 changed files with 11880 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!--
<rjw.AnimationDef>
Todo: tell Ed to uncomment start() and end() in jobdrivers
</rjw.AnimationDef>
-->
</Defs>

View File

@ -0,0 +1,660 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<Rimworld_Animations.AnimationDef>
<defName>Double_Penetration</defName>
<label>double penetration</label>
<sounds>true</sounds>
<sexTypes>
<li>DoublePenetration</li>
<li>Anal</li>
<li>Oral</li>
<li>Vaginal</li>
</sexTypes>
<actors>
<li>
<defNames>
<li>Human</li>
</defNames>
<isFucked>true</isFucked>
</li>
<li>
<defNames>
<li>Human</li>
</defNames>
<controlGenitalAngle>true</controlGenitalAngle>
<isFucking>true</isFucking>
<initiator>true</initiator>
</li>
<li>
<defNames>
<li>Human</li>
</defNames>
<controlGenitalAngle>true</controlGenitalAngle>
<isFucking>true</isFucking>
<initiator>true</initiator>
</li>
</actors>
<animationStages>
<li>
<stageName>Slow</stageName>
<isLooping>true</isLooping>
<playTimeTicks>976</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Female Pawn-->
<keyframes>
<li>
<tickDuration>25</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>35</tickDuration>
<bodyAngle>48.1</bodyAngle>
<headAngle>16.3</headAngle>
<bodyOffsetX>0</bodyOffsetX>
<bodyOffsetZ>0.188</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Suck</soundEffect>
<tickDuration>1</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Right (blow)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>-10</genitalAngle>
<tickDuration>30</tickDuration>
<bodyAngle>12</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>12</bodyAngle>
<headAngle>-15.1</headAngle>
<bodyOffsetX>0.729</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<genitalAngle>-10</genitalAngle>
<tickDuration>1</tickDuration>
<bodyAngle>12</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Left (fuck)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>27</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Fuck</soundEffect>
<tickDuration>33</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>14.1</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>1</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
</animationClips>
</li>
<li>
<stageName>Face_Fuck</stageName>
<isLooping>true</isLooping>
<playTimeTicks>650</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Female Pawn-->
<keyframes>
<li>
<tickDuration>13</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>6</tickDuration>
<bodyAngle>60.7</bodyAngle>
<headAngle>5.6</headAngle>
<bodyOffsetX>0.025</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>6</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.08</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Suck</soundEffect>
<tickDuration>1</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Right (blow)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>-10</genitalAngle>
<tickDuration>13</tickDuration>
<bodyAngle>12</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>12</tickDuration>
<bodyAngle>2</bodyAngle>
<headAngle>-15.1</headAngle>
<bodyOffsetX>0.729</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<genitalAngle>-10</genitalAngle>
<tickDuration>1</tickDuration>
<bodyAngle>12</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Left (fuck)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>13</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Fuck</soundEffect>
<tickDuration>12</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>14.1</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>1</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
</animationClips>
</li>
<li>
<stageName>Cum</stageName>
<isLooping>true</isLooping>
<playTimeTicks>392</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Female Pawn-->
<keyframes>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>4</tickDuration>
<bodyAngle>60.7</bodyAngle>
<headAngle>5.6</headAngle>
<bodyOffsetX>0.025</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>4</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.056</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Suck</soundEffect>
<tickDuration>1</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>4</tickDuration>
<bodyAngle>60.7</bodyAngle>
<headAngle>5.6</headAngle>
<bodyOffsetX>0.025</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>4</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.056</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Suck</soundEffect>
<tickDuration>1</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<quiver>true</quiver>
<tickDuration>120</tickDuration>
<bodyAngle>60.7</bodyAngle>
<headAngle>5.6</headAngle>
<bodyOffsetX>0.025</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.056</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Suck</soundEffect>
<tickDuration>1</tickDuration>
<bodyAngle>62.7</bodyAngle>
<headAngle>0.2</headAngle>
<bodyOffsetX>0.01</bodyOffsetX>
<bodyOffsetZ>0.118</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Right (blow)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>-10</genitalAngle>
<tickDuration>9</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>8</tickDuration>
<bodyAngle>0</bodyAngle>
<headAngle>-15.1</headAngle>
<bodyOffsetX>0.729</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>8</tickDuration>
<bodyAngle>0</bodyAngle>
<headAngle>-15.1</headAngle>
<bodyOffsetX>0.729</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>120</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-15.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>7</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>9</bodyAngle>
<headAngle>-14.1</headAngle>
<bodyOffsetX>0.674</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<headBob>0</headBob>
<genitalAngle>-10</genitalAngle>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<!--Male Pawn Left (fuck)-->
<layer>LayingPawn</layer>
<keyframes>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>9</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Fuck</soundEffect>
<tickDuration>8</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>14.1</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Fuck</soundEffect>
<tickDuration>8</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>14.1</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>9</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<soundEffect>Cum</soundEffect>
<tickDuration>120</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>14.1</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>-6.7</bodyAngle>
<headAngle>-7</headAngle>
<bodyOffsetX>-0.53</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
<li>
<genitalAngle>43</genitalAngle>
<tickDuration>1</tickDuration>
<bodyAngle>8.7</bodyAngle>
<headAngle>15.1</headAngle>
<bodyOffsetX>-0.70</bodyOffsetX>
<bodyOffsetZ>0.378</bodyOffsetZ>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
<headBob>0</headBob>
</li>
</keyframes>
</li>
</animationClips>
</li>
</animationStages>
</Rimworld_Animations.AnimationDef>
</Defs>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!--
<Rimworld_Animations.AnimationDef>
<defName></defName>
<label></label>
<sounds>true</sounds>
<sexTypes>
<li>Anal</li>
<li>Vaginal</li>
</sexTypes>
<actors>
<li>
<defNames>
<li>Human</li>
</defNames>
<isFucked>true</isFucked>
</li>
<li>
<defNames>
</defNames>
<bodyDefTypes>
<li>QuadrupedAnimalWithHooves</li>
<li>QuadrupedAnimalWithPawsAndTail</li>
</bodyDefTypes>
<isFucking>true</isFucking>
<initiator>true</initiator>
</li>
</actors>
<sexToyTypes>
<li>Dildo</li>
</sexToyTypes>
<animationStages>
<li>
<stageName></stageName>
<isLooping></isLooping>
<playTimeTicks></playTimeTicks>
<stageIndex>0</stageIndex>
<sexTypes>
<li>Masturbation</li>
</sexTypes>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes></keyframes>
</li>
<li Class="Rimworld_Animation.ThingAnimationClip">
</li>
</animationClips>
</li>
</animationStages>
</Rimworld_Animations.AnimationDef>
-->
</Defs>

View File

@ -0,0 +1,378 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!--
<Rimworld_Animations.AnimationDef>
<defName>Missionary</defName>
<label>missionary</label>
<sounds>true</sounds>
<sexTypes>
<li>DoublePenetration</li>
<li>Vaginal</li>
<li>Anal</li>
</sexTypes>
<actors>
<li>
<defNames>
<li>Human</li>
</defNames>
<isFucked>true</isFucked>
<bodyTypeOffset>
<Thin>(0.1, 0.1)</Thin>
</bodyTypeOffset>
</li>
<li>
<defNames>
<li>Human</li>
</defNames>
<isFucking>true</isFucking>
<initiator>true</initiator>
<bodyTypeOffset>
<Hulk>(0, 0.2)</Hulk>
</bodyTypeOffset>
</li>
</actors>
<animationStages>
<li>
<stageName>Slow_Insert</stageName>
<isLooping>false</isLooping>
<playTimeTicks>181</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<keyframes>
<li>
<tickDuration>120</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.76135</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.00123929977</bodyOffsetZ>
<bodyOffsetX>-0.288235933</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-85.3898849</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.30147323</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.78256</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.30147323</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes>
<li>
<tickDuration>120</tickDuration>
<bodyAngle>-8.415361</bodyAngle>
<headAngle>-24.7466831</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.275328381</bodyOffsetZ>
<bodyOffsetX>0.5114879</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>11.5036926</bodyAngle>
<headAngle>-10.2523956</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.226816757</bodyOffsetZ>
<bodyOffsetX>0.3989886</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<soundEffect>Slimy</soundEffect>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>3.36438</bodyAngle>
<headAngle>-18.3917084</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.233432038</bodyOffsetZ>
<bodyOffsetX>0.4034014</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
</keyframes>
</li>
</animationClips>
</li>
<li>
<stageName>Breathing</stageName>
<isLooping>true</isLooping>
<playTimeTicks>182</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<keyframes>
<li>
<tickDuration>45</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.78256</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.30147323</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>45</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.78256</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.33147323</bodyOffsetX>
<headBob>-0.03</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.78256</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.30147323</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes>
<li>
<tickDuration>45</tickDuration>
<bodyAngle>3.36438</bodyAngle>
<headAngle>-18.3917084</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.233432038</bodyOffsetZ>
<bodyOffsetX>0.4034014</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>45</tickDuration>
<bodyAngle>3.36438</bodyAngle>
<headAngle>-18.3917084</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.273432038</bodyOffsetZ>
<bodyOffsetX>0.4034014</bodyOffsetX>
<headBob>-0.03</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>3.36438</bodyAngle>
<headAngle>-18.3917084</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.233432038</bodyOffsetZ>
<bodyOffsetX>0.4034014</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
</keyframes>
</li>
</animationClips>
</li>
<li>
<stageName>Slow_Fuck_Start</stageName>
<isLooping>true</isLooping>
<playTimeTicks></playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<keyframes>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-77.78256</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.0254950486</bodyOffsetZ>
<bodyOffsetX>-0.30147323</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-72.1512451</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.025494989</bodyOffsetZ>
<bodyOffsetX>-0.29485938</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>3.36438</bodyAngle>
<headAngle>-18.3917084</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.233432038</bodyOffsetZ>
<bodyOffsetX>0.4034014</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-5.439103</bodyAngle>
<headAngle>-18.591362</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.253895342</bodyOffsetZ>
<bodyOffsetX>0.5181109</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
</keyframes>
</li>
</animationClips>
</li>
<li>
<stageName>Slow_Fuck</stageName>
<isLooping>true</isLooping>
<playTimeTicks>1212</playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<keyframes>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-72.1512451</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.025494989</bodyOffsetZ>
<bodyOffsetX>-0.29485938</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>5</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-67.51352</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.025494989</bodyOffsetZ>
<bodyOffsetX>-0.279417485</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-67.51352</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.025494989</bodyOffsetZ>
<bodyOffsetX>-0.339417485</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-82.7437439</bodyAngle>
<headAngle>-72.1512451</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.025494989</bodyOffsetZ>
<bodyOffsetX>-0.29485938</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>1</bodyFacing>
<headFacing>1</headFacing>
</li>
</keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes>
<li>
<tickDuration>30</tickDuration>
<bodyAngle>-5.439103</bodyAngle>
<headAngle>-18.591362</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.253895342</bodyOffsetZ>
<bodyOffsetX>0.5181109</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>5</tickDuration>
<bodyAngle>12.3350525</bodyAngle>
<headAngle>-14.779211</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.2605105</bodyOffsetZ>
<bodyOffsetX>0.449729085</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
<soundEffect>Fuck</soundEffect>
</li>
<li>
<tickDuration>60</tickDuration>
<bodyAngle>12.3350525</bodyAngle>
<headAngle>-14.779211</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.2605105</bodyOffsetZ>
<bodyOffsetX>0.389729085</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
<li>
<tickDuration>1</tickDuration>
<bodyAngle>-5.439103</bodyAngle>
<headAngle>-18.591362</headAngle>
<genitalAngle>0</genitalAngle>
<bodyOffsetZ>0.253895342</bodyOffsetZ>
<bodyOffsetX>0.5181109</bodyOffsetX>
<headBob>0</headBob>
<bodyFacing>3</bodyFacing>
<headFacing>3</headFacing>
</li>
</keyframes>
</li>
</animationClips>
</li>
</animationStages>
</Rimworld_Animations.AnimationDef>
-->
</Defs>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!--
<Rimworld_Animations.AnimationDef>
<defName></defName>
<label></label>
<sounds>true</sounds>
<sexTypes>
<li>Anal</li>
<li>Vaginal</li>
</sexTypes>
<actors>
<li>
<defNames>
<li>Human</li>
</defNames>
<isFucked>true</isFucked>
</li>
<li>
<defNames>
</defNames>
<bodyDefTypes>
<li>QuadrupedAnimalWithHooves</li>
<li>QuadrupedAnimalWithPawsAndTail</li>
</bodyDefTypes>
<isFucking>true</isFucking>
<initiator>true</initiator>
</li>
</actors>
<animationStages>
<li>
<stageName></stageName>
<isLooping></isLooping>
<playTimeTicks></playTimeTicks>
<stageIndex>0</stageIndex>
<animationClips>
<li Class="Rimworld_Animations.PawnAnimationClip">
<layer>LayingPawn</layer>
<keyframes></keyframes>
</li>
<li Class="Rimworld_Animations.PawnAnimationClip">
<keyframes></keyframes>
</li>
</animationClips>
</li>
</animationStages>
</Rimworld_Animations.AnimationDef>
-->
</Defs>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Defs>
<MainButtonDef>
<defName>OffsetManager</defName>
<label>offset manager</label>
<description>Control pawn offsets</description>
<tabWindowClass>Rimworld_Animations.MainTabWindow_OffsetConfigure</tabWindowClass>
<order>54</order>
<buttonVisible>false</buttonVisible>
<iconPath>UI/MainTab</iconPath>
<minimized>true</minimized>
</MainButtonDef>
</Defs>

View File

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<Defs>
<SoundDef>
<defName>Cum</defName>
<context>MapOnly</context>
<eventNames />
<maxSimultaneous>1</maxSimultaneous>
<maxVoices>1</maxVoices>
<subSounds>
<li>
<grains>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/cum</clipFolderPath>
</li>
</grains>
<volumeRange>
<min>30</min>
<max>40</max>
</volumeRange>
<pitchRange>
<min>0.8</min>
<max>1.2</max>
</pitchRange>
<distRange>
<min>0</min>
<max>51.86047</max>
</distRange>
<sustainLoop>False</sustainLoop>
</li>
</subSounds>
</SoundDef>
<SoundDef>
<defName>Sex</defName>
<context>MapOnly</context>
<eventNames />
<maxSimultaneous>1</maxSimultaneous>
<maxVoices>1</maxVoices>
<subSounds>
<li>
<grains>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/kucyu04</clipFolderPath>
</li>
</grains>
<volumeRange>
<min>16</min>
<max>16</max>
</volumeRange>
<pitchRange>
<min>0.8</min>
<max>1.2</max>
</pitchRange>
<distRange>
<min>0</min>
<max>51.86047</max>
</distRange>
<sustainLoop>False</sustainLoop>
</li>
</subSounds>
</SoundDef>
<SoundDef>
<defName>Suck</defName>
<context>MapOnly</context>
<eventNames />
<maxSimultaneous>1</maxSimultaneous>
<maxVoices>1</maxVoices>
<subSounds>
<li>
<grains>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_1</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_2</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_3</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_4</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_5</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_6</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_7</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_8</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_9</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Suck/Suck_10</clipFolderPath>
</li>
</grains>
<volumeRange>
<min>20</min>
<max>35</max>
</volumeRange>
<pitchRange>
<min>1.0</min>
<max>1.0</max>
</pitchRange>
<distRange>
<min>0</min>
<max>51.86047</max>
</distRange>
<repeatMode>NeverTwice</repeatMode>
<sustainLoop>false</sustainLoop>
</li>
</subSounds>
</SoundDef>
<SoundDef>
<defName>Fuck</defName>
<context>MapOnly</context>
<eventNames />
<maxSimultaneous>1</maxSimultaneous>
<maxVoices>1</maxVoices>
<subSounds>
<li>
<grains>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_1</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_2</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_3</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_4</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_5</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_6</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_7</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Clap_8</clipFolderPath>
</li>
</grains>
<volumeRange>
<min>45</min>
<max>70</max>
</volumeRange>
<pitchRange>
<min>1.0</min>
<max>1.0</max>
</pitchRange>
<distRange>
<min>0</min>
<max>51.86047</max>
</distRange>
<repeatMode>NeverTwice</repeatMode>
<sustainLoop>false</sustainLoop>
</li>
</subSounds>
</SoundDef>
<SoundDef>
<defName>Slimy</defName>
<context>MapOnly</context>
<eventNames />
<maxSimultaneous>1</maxSimultaneous>
<maxVoices>1</maxVoices>
<subSounds>
<li>
<grains>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Slime/Slimy1</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Slime/Slimy2</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Slime/Slimy3</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Slime/Slimy4</clipFolderPath>
</li>
<li Class="AudioGrain_Folder">
<clipFolderPath>Sex/Slime/Slimy5</clipFolderPath>
</li>
</grains>
<volumeRange>
<min>45</min>
<max>75</max>
</volumeRange>
<pitchRange>
<min>1.4</min>
<max>1.8</max>
</pitchRange>
<distRange>
<min>0</min>
<max>100</max>
</distRange>
<repeatMode>NeverTwice</repeatMode>
<sustainLoop>false</sustainLoop>
</li>
</subSounds>
</SoundDef>
</Defs>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BA766964-1716-422D-A09E-29426F8EB9D5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Patch_HatsDisplaySelection</RootNamespace>
<AssemblyName>Patch_HatsDisplaySelection</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>1.2\Assemblies\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\..\..\..\..\workshop\content\294100\2009463077\Current\Assemblies\0Harmony.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="HatDisplaySelection">
<HintPath>..\..\..\..\..\workshop\content\294100\1542291825\1.2\Assemblies\HatDisplaySelection.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Rimworld-Animations">
<HintPath>..\1.2\Assemblies\Rimworld-Animations.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="UnityEngine">
<HintPath>..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Source\Patches\Patch_HatsDisplaySelection.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="1.2\Assemblies\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>Core SK</li>
</mods>
<match Class="PatchOperationSequence">
<operations>
<li Class="PatchOperationConditional">
<xpath>Defs/ThingDef/comps</xpath>
<success>Always</success>
<nomatch Class="PatchOperationAdd">
<xpath>Defs/ThingDef</xpath>
<value>
<comps />
</value>
</nomatch>
</li>
<li Class="PatchOperationAdd">
<xpath>Defs/ThingDef[@Name="BaseAnimalPawn" or @Name="SK_BasePawn" or @Name="BasePawnSkynet"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</li>
</operations>
</match>
</Operation>
</Patch>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationAdd">
<success>Always</success>
<xpath>Defs/ThingDef[race][not(comps)]</xpath>
<value>
<comps />
</value>
</li>
<li Class="PatchOperationAdd">
<success>Always</success>
<xpath>Defs/AlienRace.ThingDef_AlienRace[not(comps)]</xpath>
<value>
<comps />
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>Defs/ThingDef[@Name="BasePawn"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>Defs/AlienRace.ThingDef_AlienRace/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</li>
</operations>
</Operation>
</Patch>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationConditional">
<xpath>/Defs/ThingDef[@Name="BaseBaseAutocleaner"]/comps</xpath>
<success>Always</success>
<match Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[@Name="BaseBaseAutocleaner"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</match>
</li>
</operations>
</Operation>
</Patch>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationConditional">
<xpath>/Defs/ThingDef[@Name="BasePawnSimple"]/comps</xpath>
<success>Always</success>
<match Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[@Name="BasePawnSimple"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</match>
</li>
</operations>
</Operation>
</Patch>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationConditional">
<xpath>/Defs/ThingDef[@Name="BaseZombie"]/comps</xpath>
<success>Always</success>
<match Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[@Name="BaseZombie"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</match>
</li>
</operations>
</Operation>
</Patch>

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>[NL] Facial Animation - WIP</li>
</mods>
<match Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationAdd">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/targetJobs</xpath>
<success>Always</success>
<value>
<li>RJW_Masturbate</li>
<li>GettinBred</li>
<li>Bestiality</li>
<li>BestialityForFemale</li>
<li>ViolateCorpse</li>
<li>Quickie</li>
<li>GettingQuickie</li>
<li>GettinRaped</li>
<li>JoinInBed</li>
<li>GettinLoved</li>
<li>GettinLicked</li>
<li>GettinSucked</li>
<li>WhoreIsServingVisitors</li>
<li>JoinInBedAnimation</li>
<li>GettinLovedAnimation</li>
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="WaitCombat" or defName="Wait_Combat_Rare"]/targetJobs</xpath>
<success>Always</success>
<value>
<li>RapeComfortPawn</li>
<li>RandomRape</li>
<li>RapeEnemy</li>
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="StandAndBeSociallyActive"]/targetJobs</xpath>
<success>Always</success>
<value>
<li>WhoreInvitingVisitors</li>
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Wear" or defName="Wear2" or defName="Wear3"]/targetJobs</xpath>
<success>Always</success>
<value>
<li>CleanSelf</li>
<li>StruggleInBondageGear</li>
</value>
</li>
<li Class="PatchOperationFindMod">
<mods>
<li>Rimworld-Animations</li>
</mods>
<match Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[1]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin"]/animationFrames/li[2]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin"]/animationFrames/li[3]/headOffset</xpath>
<success>Always</success>
</li>
</operations>
</match>
</li>
</operations>
</match>
</Operation>
</Patch>
<!--
OLD PATCH
<?xml version="1.0" encoding="utf-8"?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>[NL] Facial Animation - WIP</li>
</mods>
<match Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[1]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[2]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[3]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[4]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[5]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[6]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[7]/headOffset</xpath>
<success>Always</success>
</li>
<li Class="PatchOperationRemove">
<xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/animationFrames/li[8]/headOffset</xpath>
<success>Always</success>
</li>
</operations>
</match>
</Operation>
</Patch>
-->

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<!-- Patch for HCSK, to attach to differently written thingdefs -->
<Operation Class="PatchOperationFindMod">
<mods>
<li>Core SK</li>
</mods>
<match Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationConditional">
<xpath>/Defs/ThingDef/comps</xpath>
<success>Always</success>
<nomatch Class="PatchOperationAdd">
<xpath>/Defs/ThingDef</xpath>
<value>
<comps />
</value>
</nomatch>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[@Name="SK_BasePawn"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/ThingDef[@Name="BaseAnimalPawn"]/comps</xpath>
<value>
<li Class="Rimworld_Animations.CompProperties_BodyAnimator" />
</value>
</li>
</operations>
</match>
</Operation>
</Patch>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>Epona race Renaissance</li>
</mods>
<match Class="PatchOperationSequence">
<operations>
<li Class="PatchOperationReplace">
<xpath>/Defs/AlienRace.ThingDef_AlienRace[defName = "Alien_Epona"]/alienRace/generalSettings/alienPartGenerator/bodyAddons/li[hediffGraphics/Epona_OHPG_female="Things/Pawn/Addons/Breasts/Breasts"]/drawnInBed</xpath>
<value>
<drawnInBed>false</drawnInBed>
</value>
</li>
</operations>
</match>
</Operation>
</Patch>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>Nyaron race</li>
</mods>
<match Class="PatchOperationSequence">
<operations>
<li Class="PatchOperationAdd">
<xpath>/Defs/AlienRace.ThingDef_AlienRace[defName = "Alien_Nyaron"]/alienRace/generalSettings/alienPartGenerator/bodyAddons/li[bodyPart="tail"]</xpath>
<value>
<drawnInBed>false</drawnInBed>
</value>
</li>
</operations>
</match>
</Operation>
</Patch>

BIN
1.4/Sounds/Sex/Clap_1.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_2.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_3.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_4.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_5.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_6.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_7.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/Clap_8.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
1.4/Sounds/Sex/cum.wav Normal file

Binary file not shown.

BIN
1.4/Sounds/Sex/kucyu04.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
namespace Rimworld_Animations {
public class Actor {
public List<string> defNames;
public List<string> requiredGenitals;
public List<AlienRaceOffset> raceOffsets;
public List<string> blacklistedRaces;
public bool initiator = false;
public string gender;
public bool isFucking = false;
public bool isFucked = false;
public bool controlGenitalAngle = false;
public List<BodyDef> bodyDefTypes = new List<BodyDef>();
public BodyTypeOffset bodyTypeOffset = new BodyTypeOffset();
public Vector3 offset = new Vector2(0, 0);
public List<string> requiredGender;
public List<string> tags = new List<string>();
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Rimworld_Animations {
public class AlienRaceOffset {
public string defName;
public Vector2 offset;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace Rimworld_Animations {
public class BodyTypeOffset {
public Vector2? Male;
public Vector2? Female;
public Vector2? Thin;
public Vector2? Hulk;
public Vector2? Fat;
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rimworld_Animations {
public class AnimationStage
{
public string stageName;
public int stageIndex;
public int playTimeTicks = 0;
public int playTimeTicksQuick = -1;
public bool isLooping;
public List<BaseAnimationClip> animationClips;
public List<string> tags = new List<string>();
public void initialize() {
foreach (BaseAnimationClip clip in animationClips) {
clip.buildSimpleCurves();
//select playTimeTicks as longest playtime of all the animations
if(clip.duration > playTimeTicks) {
playTimeTicks = clip.duration;
}
}
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace Rimworld_Animations {
public abstract class BaseAnimationClip
{
public Dictionary<int, string> SoundEffects = new Dictionary<int, string>();
public List<ThingDef> types; //types of participants
public int duration;
public abstract void buildSimpleCurves();
public string soundDef = null; //for playing sounds
public int actor;
public List<string> tags = new List<string>();
}
}

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace Rimworld_Animations {
public class PawnAnimationClip : BaseAnimationClip {
public List<PawnKeyframe> keyframes;
public AltitudeLayer layer = AltitudeLayer.Pawn;
public Dictionary<int, bool> quiver = new Dictionary<int, bool>();
public SimpleCurve GenitalAngle = new SimpleCurve();
public SimpleCurve BodyAngle = new SimpleCurve();
public SimpleCurve HeadAngle = new SimpleCurve();
public SimpleCurve HeadBob = new SimpleCurve();
public SimpleCurve BodyOffsetX = new SimpleCurve();
public SimpleCurve BodyOffsetZ = new SimpleCurve();
public SimpleCurve HeadFacing = new SimpleCurve();
public SimpleCurve BodyFacing = new SimpleCurve();
public override void buildSimpleCurves() {
int duration = 0;
//getting the length of the whole clip
foreach(PawnKeyframe frame in keyframes) {
duration += frame.tickDuration;
}
//guarantees loops don't get cut off mid-anim
this.duration = duration;
int keyframePosition = 0;
foreach (PawnKeyframe frame in keyframes) {
if (frame.atTick.HasValue) {
if (frame.bodyAngle.HasValue)
BodyAngle.Add((float)frame.atTick / (float)duration, frame.bodyAngle.Value, true);
if (frame.headAngle.HasValue)
HeadAngle.Add((float)frame.atTick / (float)duration, frame.headAngle.Value, true);
if (frame.bodyOffsetX.HasValue)
BodyOffsetX.Add((float)frame.atTick / (float)duration, frame.bodyOffsetX.Value, true);
if (frame.bodyOffsetZ.HasValue)
BodyOffsetZ.Add((float)frame.atTick / (float)duration, frame.bodyOffsetZ.Value, true);
if (frame.headFacing.HasValue)
HeadFacing.Add((float)frame.atTick / (float)duration, frame.headFacing.Value, true);
if (frame.bodyFacing.HasValue)
BodyFacing.Add((float)frame.atTick / (float)duration, frame.bodyFacing.Value, true);
if (frame.headBob.HasValue)
HeadBob.Add((float)frame.atTick / (float)duration, frame.headBob.Value, true);
if (frame.genitalAngle.HasValue)
GenitalAngle.Add((float)frame.atTick / (float)duration, frame.genitalAngle.Value, true);
if (frame.soundEffect != null) {
SoundEffects.Add((int)frame.atTick, frame.soundEffect);
}
}
else {
if (frame.bodyAngle.HasValue)
BodyAngle.Add((float)keyframePosition / (float)duration, frame.bodyAngle.Value, true);
if (frame.headAngle.HasValue)
HeadAngle.Add((float)keyframePosition / (float)duration, frame.headAngle.Value, true);
if (frame.bodyOffsetX.HasValue)
BodyOffsetX.Add((float)keyframePosition / (float)duration, frame.bodyOffsetX.Value, true);
if (frame.bodyOffsetZ.HasValue)
BodyOffsetZ.Add((float)keyframePosition / (float)duration, frame.bodyOffsetZ.Value, true);
if (frame.headFacing.HasValue)
HeadFacing.Add((float)keyframePosition / (float)duration, frame.headFacing.Value, true);
if (frame.bodyFacing.HasValue)
BodyFacing.Add((float)keyframePosition / (float)duration, frame.bodyFacing.Value, true);
if (frame.headBob.HasValue)
HeadBob.Add((float)keyframePosition / (float)duration, frame.headBob.Value, true);
if (frame.genitalAngle.HasValue)
GenitalAngle.Add((float)keyframePosition / (float)duration, frame.genitalAngle.Value, true);
if (frame.soundEffect != null) {
SoundEffects.Add(keyframePosition, frame.soundEffect);
}
if(frame.tickDuration != 1 && frame.quiver.HasValue) {
quiver.Add(keyframePosition, true);
quiver.Add(keyframePosition + frame.tickDuration - 1, false);
}
keyframePosition += frame.tickDuration;
}
}
}
}
}

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using RimWorld;
namespace Rimworld_Animations {
public class ThingAnimationClip : BaseAnimationClip
{
public List<ThingKeyframe> keyframes;
public SimpleCurve PositionX = new SimpleCurve();
public SimpleCurve PositionZ = new SimpleCurve();
public SimpleCurve Rotation = new SimpleCurve();
public override void buildSimpleCurves() {
int duration = 0;
//getting the length of the whole clip
foreach (ThingKeyframe frame in keyframes)
{
duration += frame.tickDuration;
}
//guarantees loops don't get cut off mid-anim
this.duration = duration;
int keyframePosition = 0;
foreach (ThingKeyframe frame in keyframes)
{
if (frame.atTick.HasValue)
{
if (frame.positionX.HasValue)
PositionX.Add((float)frame.atTick / (float)duration, frame.positionX.Value, true);
if (frame.positionZ.HasValue)
PositionZ.Add((float)frame.atTick / (float)duration, frame.positionZ.Value, true);
if (frame.rotation.HasValue)
Rotation.Add((float)frame.atTick / (float)duration, frame.rotation.Value, true);
if (frame.soundEffect != null)
{
SoundEffects.Add((int)frame.atTick, frame.soundEffect);
}
}
else
{
if (frame.positionX.HasValue)
PositionX.Add((float)keyframePosition / (float)duration, frame.positionX.Value, true);
if (frame.positionZ.HasValue)
PositionZ.Add((float)keyframePosition / (float)duration, frame.positionZ.Value, true);
if (frame.rotation.HasValue)
Rotation.Add((float)keyframePosition / (float)duration, frame.rotation.Value, true);
if (frame.soundEffect != null)
{
SoundEffects.Add(keyframePosition, frame.soundEffect);
}
keyframePosition += frame.tickDuration;
}
}
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rimworld_Animations {
public abstract class Keyframe
{
public int tickDuration = 1;
public float? atTick;
public string soundEffect;
public List<string> tags = new List<string>();
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations {
public class PawnKeyframe : Keyframe
{
public float? bodyAngle;
public float? headAngle;
public float? genitalAngle;
public float? bodyOffsetZ;
public float? bodyOffsetX;
public float? headBob;
//todo: add headOffsets l/r?
public int? bodyFacing;
public int? headFacing;
public bool? quiver;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rimworld_Animations {
public class ThingKeyframe : Keyframe
{
public float? positionX;
public float? positionZ;
public float? rotation;
}
}

View File

@ -0,0 +1,527 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using rjw;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace Rimworld_Animations {
public class CompBodyAnimator : ThingComp
{
public Pawn pawn => base.parent as Pawn;
public PawnGraphicSet Graphics;
//public CompProperties_BodyAnimator Props => (CompProperties_BodyAnimator)(object)base.props;
public bool isAnimating {
get {
return Animating;
}
set {
Animating = value;
if (value == true) {
SexUtility.DrawNude(pawn);
} else {
pawn.Drawer.renderer.graphics.ResolveAllGraphics();
actorsInCurrentAnimation = null;
}
PortraitsCache.SetDirty(pawn);
}
}
private bool Animating = false;
private bool mirror = false, quiver = false, shiver = false;
private int actor;
private int lastDrawFrame = -1;
private int animTicks = 0, stageTicks = 0, clipTicks = 0;
private int curStage = 0;
private float clipPercent = 0;
public Vector3 anchor = Vector3.zero, deltaPos = Vector3.zero, headBob = Vector3.zero;
public float bodyAngle = 0, headAngle = 0, genitalAngle = 0;
public Rot4 headFacing = Rot4.North, bodyFacing = Rot4.North;
public List<Pawn> actorsInCurrentAnimation;
public bool controlGenitalAngle = false;
public bool fastAnimForQuickie = false;
private AnimationDef anim;
private AnimationStage stage {
get
{
return anim.animationStages[curStage];
}
}
private PawnAnimationClip clip => (PawnAnimationClip)stage.animationClips[actor];
public bool Mirror {
get {
return mirror;
}
}
public void setAnchor(IntVec3 pos)
{
anchor = pos.ToVector3Shifted();
}
public void setAnchor(Thing thing) {
//center on bed
if(thing is Building_Bed) {
anchor = thing.Position.ToVector3();
if (((Building_Bed)thing).SleepingSlotsCount == 2) {
if (thing.Rotation.AsInt == 0) {
anchor.x += 1;
anchor.z += 1;
}
else if (thing.Rotation.AsInt == 1) {
anchor.x += 1;
}
else if(thing.Rotation.AsInt == 3) {
anchor.z += 1;
}
}
else {
if(thing.Rotation.AsInt == 0) {
anchor.x += 0.5f;
anchor.z += 1f;
}
else if(thing.Rotation.AsInt == 1) {
anchor.x += 1f;
anchor.z += 0.5f;
}
else if(thing.Rotation.AsInt == 2) {
anchor.x += 0.5f;
} else {
anchor.z += 0.5f;
}
}
}
else {
anchor = thing.Position.ToVector3Shifted();
}
}
public void StartAnimation(AnimationDef anim, List<Pawn> actors, int actor, bool mirror = false, bool shiver = false, bool fastAnimForQuickie = false) {
actorsInCurrentAnimation = actors;
if (anim.actors.Count <= actor)
{
return;
}
AlienRaceOffset raceOffset = anim?.actors[actor]?.raceOffsets?.Find(x => x.defName == pawn.def.defName);
if (raceOffset != null) {
anchor.x += mirror ? raceOffset.offset.x * -1f : raceOffset.offset.x;
anchor.z += raceOffset.offset.y;
}
//change the offset based on pawn body type
if(pawn?.story?.bodyType != null) {
if (pawn.story.bodyType == BodyTypeDefOf.Fat && anim?.actors[actor]?.bodyTypeOffset?.Fat != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Fat.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Fat.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Female && anim?.actors[actor]?.bodyTypeOffset?.Female != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Female.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Female.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Male && anim?.actors[actor]?.bodyTypeOffset?.Male != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Male.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Male.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Thin && anim?.actors[actor]?.bodyTypeOffset?.Thin != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Thin.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Thin.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Hulk && anim?.actors[actor]?.bodyTypeOffset?.Hulk != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Hulk.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Hulk.Value.y;
}
}
pawn.jobs.posture = PawnPosture.Standing;
this.actor = actor;
this.anim = anim;
this.mirror = mirror;
this.fastAnimForQuickie = fastAnimForQuickie;
if (fastAnimForQuickie && anim.animationStages.Any(x => x.playTimeTicksQuick >= 0) == false)
{
curStage = 1;
animTicks = anim.animationStages[0].playTimeTicks;
} else
{
curStage = 0;
animTicks = 0;
}
stageTicks = 0;
clipTicks = 0;
quiver = false;
this.shiver = shiver && AnimationSettings.rapeShiver;
controlGenitalAngle = anim.actors[actor].controlGenitalAngle;
isAnimating = true;
//tick once for initialization
tickAnim();
}
public override void CompTick() {
base.CompTick();
if(isAnimating) {
GlobalTextureAtlasManager.TryMarkPawnFrameSetDirty(pawn);
if (pawn.Dead || pawn?.jobs?.curDriver == null || (pawn?.jobs?.curDriver != null && !(pawn?.jobs?.curDriver is rjw.JobDriver_Sex))) {
isAnimating = false;
}
else {
tickAnim();
}
}
}
public void animatePawnBody(ref Vector3 rootLoc, ref float angle, ref Rot4 bodyFacing) {
if(!isAnimating) {
return;
}
rootLoc = anchor + deltaPos;
angle = bodyAngle;
bodyFacing = this.bodyFacing;
}
public Rot4 AnimateHeadFacing()
{
return this.headFacing;
}
public void tickGraphics(PawnGraphicSet graphics) {
this.Graphics = graphics;
}
public void tickAnim() {
if (!isAnimating) return;
if (anim == null) {
isAnimating = false;
return;
}
animTicks++;
if (animTicks < anim.animationTimeTicks) {
tickStage();
} else {
if(LoopNeverending())
{
ResetOnLoop();
} else
{
isAnimating = false;
}
}
}
public void tickStage()
{
if(stage == null)
{
isAnimating = false;
return;
}
stageTicks++;
if(stageTicks >= stage.playTimeTicks || (fastAnimForQuickie && stage.playTimeTicksQuick >= 0 && stageTicks >= stage.playTimeTicksQuick)) {
curStage++;
stageTicks = 0;
clipTicks = 0;
clipPercent = 0;
}
if(curStage >= anim.animationStages.Count) {
if (LoopNeverending())
{
ResetOnLoop();
}
else
{
isAnimating = false;
pawn.jobs.curDriver.ReadyForNextToil();
}
} else {
tickClip();
}
}
public void tickClip() {
clipTicks++;
//play sound effect
if(rjw.RJWSettings.sounds_enabled && clip.SoundEffects.ContainsKey(clipTicks) && AnimationSettings.soundOverride) {
SoundInfo sound = new TargetInfo(pawn.Position, pawn.Map);
string soundEffectName = clip.SoundEffects[clipTicks];
if ((pawn.jobs.curDriver as JobDriver_Sex).isAnimalOnAnimal)
{
sound.volumeFactor *= RJWSettings.sounds_animal_on_animal_volume;
}
if(soundEffectName.StartsWith("Voiceline_"))
{
sound.volumeFactor *= RJWSettings.sounds_voice_volume;
}
if (clip.SoundEffects[clipTicks] == "Cum") {
sound.volumeFactor *= RJWSettings.sounds_cum_volume;
//considerApplyingSemen();
} else
{
sound.volumeFactor *= RJWSettings.sounds_sex_volume;
}
SoundDef.Named(soundEffectName).PlayOneShot(sound);
}
if(AnimationSettings.orgasmQuiver && clip.quiver.ContainsKey(clipTicks)) {
quiver = clip.quiver[clipTicks];
}
//loop animation if possible
if (clipPercent >= 1 && stage.isLooping) {
clipTicks = 1;//warning: don't set to zero or else calculations go wrong
}
clipPercent = (float)clipTicks / (float)clip.duration;
calculateDrawValues();
}
public void considerApplyingSemen()
{
if(AnimationSettings.applySemenOnAnimationOrgasm && (pawn?.jobs?.curDriver is JobDriver_Sex))
{
if (anim.sexTypes.Contains((pawn.jobs.curDriver as JobDriver_Sex).Sexprops.sexType))
{
//SemenHelper.calculateAndApplySemen((pawn.jobs.curDriver as JobDriver_Sex).Sexprops);
}
}
}
public void calculateDrawValues() {
/*if(Find.TickManager.TickRateMultiplier > 1 && (lastDrawFrame + 1 >= RealTime.frameCount || RealTime.deltaTime < 0.05f)) {
return;
}*/
deltaPos = new Vector3(clip.BodyOffsetX.Evaluate(clipPercent) * (mirror ? -1 : 1), clip.layer.AltitudeFor(), clip.BodyOffsetZ.Evaluate(clipPercent));
string bodyTypeDef = (pawn.story?.bodyType != null) ? pawn.story.bodyType.ToString() : "";
if (AnimationSettings.offsets != null && AnimationSettings.offsets.ContainsKey(CurrentAnimation.defName + pawn.def.defName + bodyTypeDef + ActorIndex)) {
deltaPos.x += AnimationSettings.offsets[CurrentAnimation.defName + pawn.def.defName + bodyTypeDef + ActorIndex].x * (mirror ? -1 : 1);
deltaPos.z += AnimationSettings.offsets[CurrentAnimation.defName + pawn.def.defName + bodyTypeDef + ActorIndex].y;
}
bodyAngle = (clip.BodyAngle.Evaluate(clipPercent) + (quiver || shiver ? ((Rand.Value * AnimationSettings.shiverIntensity) - (AnimationSettings.shiverIntensity / 2f)) : 0f)) * (mirror ? -1 : 1);
headAngle = clip.HeadAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
if (controlGenitalAngle) {
genitalAngle = clip.GenitalAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
}
if (AnimationSettings.rotation != null && AnimationSettings.rotation.ContainsKey(CurrentAnimation.defName + pawn.def.defName + bodyTypeDef + ActorIndex)) {
float offsetRotation = AnimationSettings.rotation[CurrentAnimation.defName + pawn.def.defName + bodyTypeDef + ActorIndex] * (Mirror ? -1 : 1);
genitalAngle += offsetRotation;
bodyAngle += offsetRotation;
headAngle += offsetRotation;
}
//don't go past 360 or less than 0
if (bodyAngle < 0) bodyAngle = 360 - ((-1f*bodyAngle) % 360);
if (bodyAngle > 360) bodyAngle %= 360;
if (headAngle < 0) headAngle = 360 - ((-1f * headAngle) % 360);
if (headAngle > 360) headAngle %= 360;
if (genitalAngle < 0) genitalAngle = 360 - ((-1f * genitalAngle) % 360);
if (genitalAngle > 360) genitalAngle %= 360;
bodyFacing = mirror ? new Rot4((int)clip.BodyFacing.Evaluate(clipPercent)).Opposite : new Rot4((int)clip.BodyFacing.Evaluate(clipPercent));
bodyFacing = new Rot4((int)clip.BodyFacing.Evaluate(clipPercent));
if(bodyFacing.IsHorizontal && mirror) {
bodyFacing = bodyFacing.Opposite;
}
headFacing = new Rot4((int)clip.HeadFacing.Evaluate(clipPercent));
if(headFacing.IsHorizontal && mirror) {
headFacing = headFacing.Opposite;
}
headBob = new Vector3(0, 0, clip.HeadBob.Evaluate(clipPercent));
lastDrawFrame = RealTime.frameCount;
}
public Vector3 getPawnHeadPosition() {
Vector3 headPos = anchor + deltaPos + Quaternion.AngleAxis(bodyAngle, Vector3.up) * (pawn.Drawer.renderer.BaseHeadOffsetAt(headFacing) + headBob);
return headPos;
}
public Vector3 getPawnHeadOffset()
{
return Quaternion.AngleAxis(bodyAngle, Vector3.up) * (pawn.Drawer.renderer.BaseHeadOffsetAt(headFacing) + headBob);
}
public AnimationDef CurrentAnimation {
get {
return anim;
}
}
public int ActorIndex {
get {
return actor;
}
}
public override void PostExposeData() {
base.PostExposeData();
Scribe_Defs.Look(ref anim, "RJWAnimations-Anim");
Scribe_Values.Look(ref animTicks, "RJWAnimations-animTicks", 1);
Scribe_Values.Look(ref stageTicks, "RJWAnimations-stageTicks", 1);
Scribe_Values.Look(ref clipTicks, "RJWAnimations-clipTicks", 1);
Scribe_Values.Look(ref clipPercent, "RJWAnimations-clipPercent", 1);
Scribe_Values.Look(ref mirror, "RJWAnimations-mirror");
Scribe_Values.Look(ref curStage, "RJWAnimations-curStage", 0);
Scribe_Values.Look(ref actor, "RJWAnimations-actor");
Scribe_Values.Look(ref anchor, "RJWAnimations-anchor");
Scribe_Values.Look(ref deltaPos, "RJWAnimations-deltaPos");
Scribe_Values.Look(ref headBob, "RJWAnimations-headBob");
Scribe_Values.Look(ref bodyAngle, "RJWAnimations-bodyAngle");
Scribe_Values.Look(ref headAngle, "RJWAnimations-headAngle");
Scribe_Values.Look(ref genitalAngle, "RJWAnimations-GenitalAngle");
Scribe_Values.Look(ref controlGenitalAngle, "RJWAnimations-controlGenitalAngle");
Scribe_Values.Look(ref headFacing, "RJWAnimations-headFacing");
Scribe_Values.Look(ref headFacing, "RJWAnimations-bodyFacing");
Scribe_Values.Look(ref quiver, "RJWAnimations-orgasmQuiver");
}
public void shiftActorPositionAndRestartAnimation() {
actor = (actor == anim.actors.Count - 1 ? 0 : actor + 1);
if (pawn?.story?.bodyType != null) {
if (pawn.story.bodyType == BodyTypeDefOf.Fat && anim?.actors[actor]?.bodyTypeOffset?.Fat != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Fat.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Fat.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Female && anim?.actors[actor]?.bodyTypeOffset?.Female != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Female.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Female.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Male && anim?.actors[actor]?.bodyTypeOffset?.Male != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Male.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Male.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Thin && anim?.actors[actor]?.bodyTypeOffset?.Thin != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Thin.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Thin.Value.y;
}
else if (pawn.story.bodyType == BodyTypeDefOf.Hulk && anim?.actors[actor]?.bodyTypeOffset?.Hulk != null) {
anchor.x += anim.actors[actor].bodyTypeOffset.Hulk.Value.x * (mirror ? -1f : 1f);
anchor.z += anim.actors[actor].bodyTypeOffset.Hulk.Value.y;
}
}
curStage = 0;
animTicks = 0;
stageTicks = 0;
clipTicks = 0;
controlGenitalAngle = anim.actors[actor].controlGenitalAngle;
tickAnim();
}
public bool LoopNeverending()
{
if(pawn?.jobs?.curDriver != null &&
(pawn.jobs.curDriver is JobDriver_Sex) && (pawn.jobs.curDriver as JobDriver_Sex).neverendingsex ||
(pawn.jobs.curDriver is JobDriver_SexBaseReciever) && (pawn.jobs.curDriver as JobDriver_Sex).Partner?.jobs?.curDriver != null && ((pawn.jobs.curDriver as JobDriver_Sex).Partner.jobs.curDriver as JobDriver_Sex).neverendingsex)
{
return true;
}
return false;
}
public void ResetOnLoop()
{
curStage = 1;
animTicks = 0;
stageTicks = 0;
clipTicks = 0;
tickAnim();
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using RimWorld;
namespace Rimworld_Animations {
public class CompProperties_BodyAnimator : CompProperties
{
public CompProperties_BodyAnimator()
{
base.compClass = typeof(CompBodyAnimator);
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations {
public class CompProperties_ThingAnimator : CompProperties
{
public CompProperties_ThingAnimator()
{
base.compClass = typeof(CompThingAnimator);
}
}
}

View File

@ -0,0 +1,245 @@
using RimWorld;
using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
namespace Rimworld_Animations {
public class CompThingAnimator : ThingComp
{
Vector3 anchor;
Pawn pawn;
public bool isAnimating = false, mirror;
int animTicks = 0, stageTicks = 0, clipTicks = 0, curStage = 0;
float rotation = 0;
float clipPercent = 0;
public Vector3 deltaPos;
AnimationDef anim;
private ThingAnimationClip clip => (ThingAnimationClip)stage.animationClips[1];
private AnimationStage stage
{
get
{
return anim.animationStages[curStage];
}
}
public void StartAnimation(AnimationDef anim, Pawn pawn, bool mirror = false)
{
isAnimating = true;
this.anim = anim;
this.pawn = pawn;
this.mirror = mirror;
animTicks = 0;
stageTicks = 0;
clipTicks = 0;
curStage = 0;
clipPercent = 0;
tickAnim();
}
public void setAnchor(IntVec3 position)
{
anchor = position.ToVector3();
}
public override void CompTick()
{
base.CompTick();
if(isAnimating)
{
if (pawn.Dead || pawn?.jobs?.curDriver == null || (pawn?.jobs?.curDriver != null && !(pawn?.jobs?.curDriver is rjw.JobDriver_Sex)))
{
isAnimating = false;
}
else
{
tickAnim();
}
}
}
public void tickAnim()
{
if (!isAnimating) return;
animTicks++;
if (animTicks < anim.animationTimeTicks)
{
tickStage();
}
else
{
if (LoopNeverending())
{
ResetOnLoop();
}
else
{
isAnimating = false;
}
}
}
public void tickStage()
{
if (stage == null)
{
isAnimating = false;
return;
}
stageTicks++;
if (stageTicks >= stage.playTimeTicks)
{
curStage++;
stageTicks = 0;
clipTicks = 0;
clipPercent = 0;
}
if (curStage >= anim.animationStages.Count)
{
if (LoopNeverending())
{
ResetOnLoop();
}
else
{
isAnimating = false;
}
}
else
{
tickClip();
}
}
public void tickClip()
{
clipTicks++;
if (clipPercent >= 1 && stage.isLooping)
{
clipTicks = 1;//warning: don't set to zero or else calculations go wrong
}
clipPercent = (float)clipTicks / (float)clip.duration;
calculateDrawValues();
}
public void setAnchor(Thing thing)
{
//center on bed
if (thing is Building_Bed)
{
anchor = thing.Position.ToVector3();
if (((Building_Bed)thing).SleepingSlotsCount == 2)
{
if (thing.Rotation.AsInt == 0)
{
anchor.x += 1;
anchor.z += 1;
}
else if (thing.Rotation.AsInt == 1)
{
anchor.x += 1;
}
else if (thing.Rotation.AsInt == 3)
{
anchor.z += 1;
}
}
else
{
if (thing.Rotation.AsInt == 0)
{
anchor.x += 0.5f;
anchor.z += 1f;
}
else if (thing.Rotation.AsInt == 1)
{
anchor.x += 1f;
anchor.z += 0.5f;
}
else if (thing.Rotation.AsInt == 2)
{
anchor.x += 0.5f;
}
else
{
anchor.z += 0.5f;
}
}
}
else
{
anchor = thing.Position.ToVector3Shifted();
}
anchor -= new Vector3(0.5f, 0, 0.5f);
}
private void calculateDrawValues()
{
//shift up and right 0.5f to align center
deltaPos = new Vector3((clip.PositionX.Evaluate(clipPercent)) * (mirror ? -1 : 1) + 0.5f, AltitudeLayer.Item.AltitudeFor(), clip.PositionZ.Evaluate(clipPercent) + 0.5f);
//Log.Message("Clip percent: " + clipPercent + " deltaPos: " + deltaPos);
rotation = clip.Rotation.Evaluate(clipPercent) * (mirror ? -1 : 1);
}
public void AnimateThing(Thing thing)
{
thing.Graphic.Draw(deltaPos + anchor, mirror ? Rot4.West : Rot4.East, thing, rotation);
}
public bool LoopNeverending()
{
if (pawn?.jobs?.curDriver != null &&
(pawn.jobs.curDriver is JobDriver_Sex) && (pawn.jobs.curDriver as JobDriver_Sex).neverendingsex)
{
return true;
}
return false;
}
public void ResetOnLoop()
{
curStage = 1;
animTicks = 0;
stageTicks = 0;
clipTicks = 0;
tickAnim();
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
namespace Rimworld_Animations {
public class AnimationDef : Def
{
public List<AnimationStage> animationStages;
public List<Actor> actors;
public int animationTimeTicks = 0; //do not set manually
public bool sounds = false;
public List<rjw.xxx.rjwSextype> sexTypes = null;
public List<String> interactionDefTypes = null;
public List<string> tags = new List<string>();
public override void PostLoad() {
base.PostLoad();
foreach(AnimationStage stage in animationStages) {
stage.initialize();
animationTimeTicks += stage.playTimeTicks;
}
}
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using Rimworld_Animations;
namespace Rimworld_Animations
{
[StaticConstructorOnStartup]
public static class PawnWoundDrawerExtension
{
public static void RenderOverBody(this PawnWoundDrawer pawnWoundDrawer, Vector3 drawLoc, Mesh bodyMesh, Quaternion quat, bool drawNow, BodyTypeDef.WoundLayer layer, Rot4 pawnRot, bool? overApparel = null, Pawn pawn = null, PawnRenderFlags flags = new PawnRenderFlags())
{
if (pawn == null)
{ return; }
if (!flags.FlagSet(PawnRenderFlags.Portrait) && layer == BodyTypeDef.WoundLayer.Head)
{
CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
if (pawnAnimator != null && pawnAnimator.isAnimating && pawn.Drawer.renderer.graphics.headGraphic != null)
{
pawnRot = pawnAnimator.headFacing;
quat = Quaternion.AngleAxis(angle: pawnAnimator.headAngle, axis: Vector3.up);
float y = drawLoc.y;
drawLoc = pawnAnimator.getPawnHeadPosition() - Quaternion.AngleAxis(pawnAnimator.headAngle, Vector3.up) * pawn.Drawer.renderer.BaseHeadOffsetAt(pawnAnimator.headFacing);
drawLoc.y = y;
}
}
pawnWoundDrawer.RenderOverBody(drawLoc, bodyMesh, quat, drawNow, layer, pawnRot, overApparel);
}
}
}

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using RimWorld;
using UnityEngine;
namespace Rimworld_Animations {
class MainTabWindow_OffsetConfigure : MainTabWindow
{
public override Vector2 RequestedTabSize => new Vector2(505, 380);
public override void DoWindowContents(Rect inRect) {
Rect position = new Rect(inRect.x, inRect.y, inRect.width, inRect.height);
Listing_Standard listingStandard = new Listing_Standard();
listingStandard.Begin(position);
listingStandard.Label("Animation Manager");
listingStandard.GapLine();
if (Find.Selector.SingleSelectedThing is Pawn) {
Pawn curPawn = Find.Selector.SingleSelectedThing as Pawn;
if (curPawn.TryGetComp<CompBodyAnimator>().isAnimating) {
AnimationDef def = curPawn.TryGetComp<CompBodyAnimator>().CurrentAnimation;
int ActorIndex = curPawn.TryGetComp<CompBodyAnimator>().ActorIndex;
float offsetX = 0, offsetZ = 0, rotation = 0;
string bodyTypeDef = (curPawn.story?.bodyType != null) ? curPawn.story.bodyType.ToString() : "";
if (AnimationSettings.offsets.ContainsKey(def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex)) {
offsetX = AnimationSettings.offsets[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex].x;
offsetZ = AnimationSettings.offsets[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex].y;
} else {
AnimationSettings.offsets.Add(def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex, new Vector2(0, 0));
}
if (AnimationSettings.rotation.ContainsKey(def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex)) {
rotation = AnimationSettings.rotation[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex];
}
else {
AnimationSettings.rotation.Add(def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex, 0);
}
listingStandard.Label("Name: " + curPawn.Name + " Race: " + curPawn.def.defName + " Actor Index: " + curPawn.TryGetComp<CompBodyAnimator>().ActorIndex + " Body Type (if any): " + bodyTypeDef + " Animation: " + def.label + (curPawn.TryGetComp<CompBodyAnimator>().Mirror ? " mirrored" : ""));
if(curPawn.def.defName == "Human") {
listingStandard.Label("Warning--You generally don't want to change human offsets, only alien offsets");
}
bool mirrored = curPawn.TryGetComp<CompBodyAnimator>().Mirror;
float.TryParse(listingStandard.TextEntryLabeled("X Offset: ", offsetX.ToString()), out offsetX);
offsetX = listingStandard.Slider(offsetX, -2 * (mirrored ? -1 : 1), 2 * (mirrored ? -1 : 1));
float.TryParse(listingStandard.TextEntryLabeled("Z Offset: ", offsetZ.ToString()), out offsetZ);
offsetZ = listingStandard.Slider(offsetZ, -2, 2);
float.TryParse(listingStandard.TextEntryLabeled("Rotation: ", rotation.ToString()), out rotation);
rotation = listingStandard.Slider(rotation, -180, 180);
if(listingStandard.ButtonText("Reset All")) {
offsetX = 0;
offsetZ = 0;
rotation = 0;
}
listingStandard.GapLine();
if(listingStandard.ButtonText("Shift Actors")) {
if(AnimationSettings.debugMode) {
Log.Message("Shifting actors in animation...");
}
for(int i = 0; i < curPawn.TryGetComp<CompBodyAnimator>().actorsInCurrentAnimation.Count; i++) {
Pawn actor = curPawn.TryGetComp<CompBodyAnimator>().actorsInCurrentAnimation[i];
actor.TryGetComp<CompBodyAnimator>()?.shiftActorPositionAndRestartAnimation();
//reset the clock time of every pawn in animation
if(actor.jobs.curDriver is rjw.JobDriver_Sex) {
(actor.jobs.curDriver as rjw.JobDriver_Sex).ticks_left = def.animationTimeTicks;
(actor.jobs.curDriver as rjw.JobDriver_Sex).ticksLeftThisToil = def.animationTimeTicks;
(actor.jobs.curDriver as rjw.JobDriver_Sex).duration = def.animationTimeTicks;
}
}
}
if (offsetX != AnimationSettings.offsets[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex].x || offsetZ != AnimationSettings.offsets[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex].y) {
AnimationSettings.offsets[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex] = new Vector2(offsetX, offsetZ);
}
if(rotation != AnimationSettings.rotation[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex]) {
AnimationSettings.rotation[def.defName + curPawn.def.defName + bodyTypeDef + ActorIndex] = rotation;
}
}
}
else {
listingStandard.Label("Select a pawn currently in an animation to change their offsets");
}
listingStandard.End();
}
public override void PreOpen() {
base.PreOpen();
if(AnimationSettings.offsets == null) {
if (AnimationSettings.debugMode)
Log.Message("New offsets");
AnimationSettings.offsets = new Dictionary<string, Vector2>();
}
if(AnimationSettings.rotation == null) {
if (AnimationSettings.debugMode)
Log.Message("New rotation");
AnimationSettings.rotation = new Dictionary<string, float>();
}
}
public override void PostClose() {
base.PostClose();
LoadedModManager.GetMod<RJW_Animations>().WriteSettings();
}
}
}

View File

@ -0,0 +1,22 @@
using RimWorld;
using Verse;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rimworld_Animations {
[DefOf]
public static class OffsetMainButtonDefOf {
public static MainButtonDef OffsetManager;
static OffsetMainButtonDefOf() {
DefOfHelper.EnsureInitializedInCtor(typeof(OffsetMainButtonDefOf));
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using RimWorld.Planet;
using Verse;
namespace Rimworld_Animations {
public class WorldComponent_UpdateMainTab : WorldComponent {
public WorldComponent_UpdateMainTab(World world) : base(world) {
}
public override void FinalizeInit() {
base.FinalizeInit();
OffsetMainButtonDefOf.OffsetManager.buttonVisible = AnimationSettings.offsetTab;
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using HarmonyLib;
using System.Reflection;
namespace Rimworld_Animations {
[StaticConstructorOnStartup]
public static class Harmony_PatchAll {
static Harmony_PatchAll() {
Harmony val = new Harmony("rjwanim");
val.PatchAll(Assembly.GetExecutingAssembly());
}
}
}

View File

@ -0,0 +1,397 @@
using HarmonyLib;
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;
using AlienRace;
namespace Rimworld_Animations {
[StaticConstructorOnStartup]
public static class HarmonyPatch_AlienRace
{
static HarmonyPatch_AlienRace()
{
(new Harmony("rjwanim")).Patch(AccessTools.Method(AccessTools.TypeByName("AlienRace.HarmonyPatches"), "DrawAddons"),
prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_AlienRace), "Prefix_AnimateHeadAddons")));
}
public static bool Prefix_AnimateHeadAddons(PawnRenderFlags renderFlags, Vector3 vector /*rootloc*/, Vector3 headOffset, Pawn pawn, Quaternion quat, Rot4 rotation)
{
if (renderFlags.FlagSet(PawnRenderFlags.Portrait) || pawn.TryGetComp<CompBodyAnimator>() == null || !pawn.TryGetComp<CompBodyAnimator>().isAnimating) return true;
if (!(pawn.def is ThingDef_AlienRace alienProps) || renderFlags.FlagSet(PawnRenderFlags.Invisible)) return false;
List<AlienPartGenerator.BodyAddon> addons = alienProps.alienRace.generalSettings.alienPartGenerator.bodyAddons;
AlienPartGenerator.AlienComp comp = pawn.GetComp<AlienPartGenerator.AlienComp>();
CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
for (int i = 0; i < addons.Count; i++)
{
AlienPartGenerator.BodyAddon ba = addons[index: i];
if (!ba.CanDrawAddon(pawn: pawn)) continue;
bool forceDrawForBody = false;
if (alienProps.defName.Contains("Orassan") && ba.path.ToLower().Contains("tail"))
{
forceDrawForBody = true;
}
AlienPartGenerator.RotationOffset offset = ba.defaultOffsets.GetOffset((ba.drawnInBed && !forceDrawForBody) || ba.alignWithHead ? pawnAnimator.headFacing : pawnAnimator.bodyFacing);
Vector3 a = (offset != null) ? offset.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero;
AlienPartGenerator.RotationOffset offset2 = ba.offsets.GetOffset((ba.drawnInBed && !forceDrawForBody) || ba.alignWithHead ? pawnAnimator.headFacing : pawnAnimator.bodyFacing);
Vector3 vector2 = a + ((offset2 != null) ? offset2.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero);
vector2.y = (ba.inFrontOfBody ? (0.3f + vector2.y) : (-0.3f - vector2.y));
float num = ba.angle;
if (rotation == Rot4.North)
{
if (ba.layerInvert)
{
vector2.y = 0f - vector2.y;
}
num = 0f;
}
if (rotation == Rot4.East)
{
num = 0f - num;
vector2.x = 0f - vector2.x;
}
Graphic addonGraphic = comp.addonGraphics[i];
addonGraphic.drawSize = ((renderFlags.FlagSet(PawnRenderFlags.Portrait) && ba.drawSizePortrait != Vector2.zero) ? ba.drawSizePortrait : ba.drawSize) * (ba.scaleWithPawnDrawsize ? (ba.alignWithHead ? (renderFlags.FlagSet(PawnRenderFlags.Portrait) ? comp.customPortraitHeadDrawSize : comp.customHeadDrawSize) : (renderFlags.FlagSet(PawnRenderFlags.Portrait) ? comp.customPortraitDrawSize : comp.customDrawSize)) : Vector2.one) * 1.5f;
Vector3 orassanv = Vector3.zero;
bool orassan = false;
if ((pawn.def as ThingDef_AlienRace).defName == "Alien_Orassan")
{
orassan = true;
if (ba.path.Contains("closed"))
{
continue;
}
if (ba.bodyPart.Contains("ear"))
{
orassan = true;
orassanv = new Vector3(0, 0, 0.23f);
if (pawnAnimator.headFacing == Rot4.North)
{
orassanv.z -= 0.1f;
orassanv.y += 1f;
if (ba.bodyPart.Contains("left"))
{
orassanv.x += 0.03f;
}
else
{
orassanv.x -= 0.03f;
}
}
else if (pawnAnimator.headFacing == Rot4.East)
{
orassanv.x -= 0.1f;
}
else if (pawnAnimator.headFacing == Rot4.West)
{
orassanv.x = 0.1f;
}
else
{
orassanv.z -= 0.1f;
orassanv.y += 1f;
if (ba.bodyPart.Contains("right"))
{
//orassanv.x += 0.3f;
}
else
{
//orassanv.x -= 0.3f;
}
}
orassanv = orassanv.RotatedBy(pawnAnimator.headAngle);
}
}
if ((ba.drawnInBed && !forceDrawForBody) || ba.alignWithHead)
{
Quaternion addonRotation = Quaternion.AngleAxis(pawnAnimator.headAngle < 0 ? 360 - (360 % pawnAnimator.headAngle) : pawnAnimator.headAngle, Vector3.up);
/*
*
* genital rotation is borked
if (AnimationSettings.controlGenitalRotation && pawnAnimator.controlGenitalAngle && ba?.hediffGraphics != null && ba.hediffGraphics.Count != 0 && ba.hediffGraphics[0]?.path != null && (ba.hediffGraphics[0].path.Contains("Penis") || ba.hediffGraphics[0].path.Contains("penis")))
{
addonRotation = Quaternion.AngleAxis(angle: pawnAnimator.genitalAngle < 0 ? 360 - (360 % pawnAnimator.genitalAngle) : pawnAnimator.genitalAngle, axis: Vector3.up);
}
*/
GenDraw.DrawMeshNowOrLater(mesh: addonGraphic.MeshAt(rot: pawnAnimator.headFacing), loc: vector /*rootloc*/ + orassanv + (ba.alignWithHead && !orassan ? headOffset : headOffset - addonRotation * pawn.Drawer.renderer.BaseHeadOffsetAt(pawnAnimator.headFacing)) + vector2.RotatedBy(angle: Mathf.Acos(f: Quaternion.Dot(a: Quaternion.identity, b: addonRotation)) * 2f * 57.29578f),
quat: Quaternion.AngleAxis(angle: num, axis: Vector3.up) * addonRotation, mat: addonGraphic.MatAt(rot: pawnAnimator.headFacing), renderFlags.FlagSet(PawnRenderFlags.DrawNow));
}
else
{
Quaternion addonRotation = Quaternion.AngleAxis(pawnAnimator.bodyAngle, Vector3.up);
if (AnimationSettings.controlGenitalRotation && pawnAnimator.controlGenitalAngle && ba?.hediffGraphics != null && ba.hediffGraphics.Count != 0 && ba.hediffGraphics[0]?.path != null && (ba.hediffGraphics[0].path.Contains("Penis") || ba.hediffGraphics[0].path.Contains("penis")))
{
GenDraw.DrawMeshNowOrLater(mesh: addonGraphic.MeshAt(rot: rotation), loc: vector + (ba.alignWithHead ? headOffset : Vector3.zero) + vector2.RotatedBy(angle: Mathf.Acos(f: Quaternion.Dot(a: Quaternion.identity, b: addonRotation)) * 2f * 57.29578f),
quat: Quaternion.AngleAxis(angle: pawnAnimator.genitalAngle, axis: Vector3.up), mat: addonGraphic.MatAt(rot: rotation), renderFlags.FlagSet(PawnRenderFlags.DrawNow));
}
else
{
GenDraw.DrawMeshNowOrLater(mesh: addonGraphic.MeshAt(rot: rotation), loc: vector + (ba.alignWithHead ? headOffset : Vector3.zero) + vector2.RotatedBy(angle: Mathf.Acos(f: Quaternion.Dot(a: Quaternion.identity, b: addonRotation)) * 2f * 57.29578f),
quat: Quaternion.AngleAxis(angle: num, axis: Vector3.up) * addonRotation, mat: addonGraphic.MatAt(rot: rotation), renderFlags.FlagSet(PawnRenderFlags.DrawNow));
}
}
}
return false;
}
}
[HarmonyPatch(typeof(PawnGraphicSet), "ResolveApparelGraphics")]
public static class HarmonyPatch_ResolveApparelGraphics
{
public static bool Prefix(ref Pawn ___pawn)
{
if (___pawn.TryGetComp<CompBodyAnimator>() != null && ___pawn.TryGetComp<CompBodyAnimator>().isAnimating)
{
return false;
}
return true;
}
}
/*
[HarmonyPatch(typeof(AlienRace.HarmonyPatches), "DrawAddons")]
public static class HarmonyPatch_AlienRace {
public static void RenderHeadAddonInAnimation(Mesh mesh, Vector3 loc, Quaternion quat, Material mat, bool drawNow, Graphic graphic, AlienPartGenerator.BodyAddon bodyAddon, Vector3 v, Vector3 headOffset, Pawn pawn, PawnRenderFlags renderFlags, Vector3 vector, Rot4 rotation)
{
CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
AlienPartGenerator.AlienComp comp = pawn.GetComp<AlienPartGenerator.AlienComp>();
if (pawnAnimator != null && pawnAnimator.isAnimating)
{
if((bodyAddon.drawnInBed || bodyAddon.alignWithHead))
{
AlienPartGenerator.RotationOffset offset = bodyAddon.defaultOffsets.GetOffset(rotation);
Vector3 a = (offset != null) ? offset.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero;
AlienPartGenerator.RotationOffset offset2 = bodyAddon.offsets.GetOffset(rotation);
Vector3 vector2 = a + ((offset2 != null) ? offset2.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero);
vector2.y = (bodyAddon.inFrontOfBody ? (0.3f + vector2.y) : (-0.3f - vector2.y));
float num = bodyAddon.angle;
if (rotation == Rot4.North)
{
if (bodyAddon.layerInvert)
{
vector2.y = -vector2.y;
}
num = 0f;
}
if (rotation == Rot4.East)
{
num = -num;
vector2.x = -vector2.x;
}
vector = vector + Quaternion.AngleAxis(pawnAnimator.bodyAngle, Vector3.up) * pawn.Drawer.renderer.BaseHeadOffsetAt(pawnAnimator.bodyFacing) - pawnAnimator.getPawnHeadOffset(); //convert vector into pseudo body pos for head
quat = Quaternion.AngleAxis(pawnAnimator.headAngle, Vector3.up);
loc = vector + (bodyAddon.alignWithHead ? headOffset : Vector3.zero) + vector2.RotatedBy(Mathf.Acos(Quaternion.Dot(Quaternion.identity, quat)) * 2f * 57.29578f);
mat = graphic.MatAt(rot: pawnAnimator.headFacing);
}
else
{
AlienPartGenerator.RotationOffset offset = bodyAddon.defaultOffsets.GetOffset(rotation);
Vector3 a = (offset != null) ? offset.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero;
AlienPartGenerator.RotationOffset offset2 = bodyAddon.offsets.GetOffset(rotation);
Vector3 vector2 = a + ((offset2 != null) ? offset2.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, comp.crownType) : Vector3.zero);
vector2.y = (bodyAddon.inFrontOfBody ? (0.3f + vector2.y) : (-0.3f - vector2.y));
float num = bodyAddon.angle;
if (rotation == Rot4.North)
{
if (bodyAddon.layerInvert)
{
vector2.y = -vector2.y;
}
num = 0f;
}
if (rotation == Rot4.East)
{
num = -num;
vector2.x = -vector2.x;
}
quat = Quaternion.AngleAxis(pawnAnimator.bodyAngle, Vector3.up);
loc = vector + (bodyAddon.alignWithHead ? headOffset : Vector3.zero) + vector2.RotatedBy(Mathf.Acos(Quaternion.Dot(Quaternion.identity, quat)) * 2f * 57.29578f);
}
}
GenDraw.DrawMeshNowOrLater(mesh, loc, quat, mat, drawNow);
/*
if (pawnAnimator != null && !renderFlags.FlagSet(PawnRenderFlags.Portrait) && pawnAnimator.isAnimating && (bodyAddon.drawnInBed || bodyAddon.alignWithHead))
{
if ((pawn.def as ThingDef_AlienRace).defName == "Alien_Orassan")
{
orassan = true;
if(bodyAddon.path.Contains("closed"))
{
return;
}
if (bodyAddon.bodyPart.Contains("ear"))
{
orassan = true;
orassanv = new Vector3(0, 0, 0.23f);
if (pawnAnimator.headFacing == Rot4.North)
{
orassanv.z -= 0.1f;
orassanv.y += 1f;
if(bodyAddon.bodyPart.Contains("left"))
{
orassanv.x += 0.03f;
} else
{
orassanv.x -= 0.03f;
}
}
else if (pawnAnimator.headFacing == Rot4.East)
{
orassanv.x -= 0.1f;
}
else if (pawnAnimator.headFacing == Rot4.West)
{
orassanv.x = 0.1f;
}
else
{
orassanv.z -= 0.1f;
orassanv.y += 1f;
if (bodyAddon.bodyPart.Contains("right"))
{
orassanv.x += 0.05f;
}
else
{
orassanv.x -= 0.05f;
}
}
orassanv = orassanv.RotatedBy(pawnAnimator.headAngle);
}
}
GenDraw.DrawMeshNowOrLater(mesh: graphic.MeshAt(rot: headRotInAnimation), loc: loc + orassanv + (bodyAddon.alignWithHead ? headOffset : Vector3.zero),// + v.RotatedBy(Mathf.Acos(Quaternion.Dot(Quaternion.identity, quat)) * 2f * 57.29578f),
quat: Quaternion.AngleAxis(angle: num, axis: Vector3.up) * headQuatInAnimation, mat: graphic.MatAt(rot: pawnAnimator.headFacing), drawNow: drawNow);;
}
else
{
}
}
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> ins = instructions.ToList();
for (int i = 0; i < ins.Count; i++)
{
Type[] type = new Type[] { typeof(Mesh), typeof(Vector3), typeof(Quaternion), typeof(Material), typeof(bool) };
if (ins[i].OperandIs(AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater", type)))
{
yield return new CodeInstruction(OpCodes.Ldloc, (object)7); //graphic
yield return new CodeInstruction(OpCodes.Ldloc, (object)4); //bodyAddon
yield return new CodeInstruction(OpCodes.Ldloc, (object)5); //offsetVector/AddonOffset (v)
yield return new CodeInstruction(OpCodes.Ldarg, (object)2); //headOffset
yield return new CodeInstruction(OpCodes.Ldarg, (object)3); //pawn
yield return new CodeInstruction(OpCodes.Ldarg, (object)0); //renderflags
yield return new CodeInstruction(OpCodes.Ldarg, (object)1); //vector
yield return new CodeInstruction(OpCodes.Ldarg, (object)5); //rotation
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(HarmonyPatch_AlienRace), "RenderHeadAddonInAnimation"));
}
else
{
yield return ins[i];
}
}
}
public static bool Prefix(PawnRenderFlags renderFlags, ref Vector3 vector, ref Vector3 headOffset, Pawn pawn, ref Quaternion quat, ref Rot4 rotation)
{
if(pawn == null)
{
return true;
}
CompBodyAnimator anim = pawn.TryGetComp<CompBodyAnimator>();
if(anim == null)
{
return true;
}
if (anim != null && !renderFlags.FlagSet(PawnRenderFlags.Portrait) && anim.isAnimating)
{
//quat = Quaternion.AngleAxis(anim.bodyAngle, Vector3.up);
}
return true;
}
}
*/
}

View File

@ -0,0 +1,87 @@
/*
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using rjw;
using Verse;
using RimWorld;
using System.Reflection.Emit;
using System.Reflection;
using UnityEngine;
namespace Rimworld_Animations {
[StaticConstructorOnStartup]
public static class HarmonyPatch_CSL {
static HarmonyPatch_CSL() {
try {
((Action)(() => {
if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "Children, school and learning")) {
(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("Children.PawnRenderer_RenderPawnInternal_Patch"), "RenderPawnInternalScaled"),
prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_CSL), "Prefix_CSL")),
transpiler: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_CSL), "Transpiler_CSL")));
}
}))();
}
catch (TypeLoadException ex) {
}
}
public static void Prefix_CSL(PawnRenderer __instance, Pawn pawn, ref Vector3 rootLoc, ref float angle, bool renderBody, ref Rot4 bodyFacing, ref Rot4 headFacing, RotDrawMode bodyDrawType, bool portrait, bool headStump, bool invisible) {
PawnGraphicSet graphics = __instance.graphics;
CompBodyAnimator bodyAnim = pawn.TryGetComp<CompBodyAnimator>();
if (!graphics.AllResolved) {
graphics.ResolveAllGraphics();
}
if (bodyAnim != null && bodyAnim.isAnimating && !portrait) {
bodyAnim.tickGraphics(graphics);
pawn.TryGetComp<CompBodyAnimator>().animatePawn(ref rootLoc, ref angle, ref bodyFacing, ref headFacing);
}
}
public static IEnumerable<CodeInstruction> Transpiler_CSL(IEnumerable<CodeInstruction> instructions) {
MethodInfo drawMeshNowOrLater = AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater");
FieldInfo headGraphic = AccessTools.Field(typeof(PawnGraphicSet), "headGraphic");
List<CodeInstruction> codes = instructions.ToList();
bool forHead = true;
for (int i = 0; i < codes.Count(); i++) {
//Instead of calling drawmeshnoworlater, add pawn to the stack and call my special static method
if (codes[i].OperandIs(drawMeshNowOrLater) && forHead) {
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
yield return new CodeInstruction(OpCodes.Ldarg_2);
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), nameof(AnimationUtility.RenderPawnHeadMeshInAnimation), new Type[] { typeof(Mesh), typeof(Vector3), typeof(Quaternion), typeof(Material), typeof(bool), typeof(Pawn), typeof(float) }));
}
//checking for if(graphics.headGraphic != null)
else if (codes[i].opcode == OpCodes.Ldfld && codes[i].OperandIs(headGraphic)) {
forHead = true;
yield return codes[i];
}
//checking for if(renderbody)
else if (codes[i].opcode == OpCodes.Ldarg_3) {
forHead = false;
yield return codes[i];
}
else {
yield return codes[i];
}
}
}
}
}*/

View File

@ -0,0 +1,29 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations {
class HarmonyPatch_DontShaveYourHead {
[StaticConstructorOnStartup]
public static class Patch_DontShaveYourHead {
static Patch_DontShaveYourHead() {
try {
((Action)(() =>
{
if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "Don't Shave Your Head 1.0")) {
(new Harmony("rjwanim")).Patch(AccessTools.Method(AccessTools.TypeByName("DontShaveYourHead.Harmony_PawnRenderer"), "DrawHairReroute"), //typeof(ShowHair.Patch_PawnRenderer_RenderPawnInternal), nameof(ShowHair.Patch_PawnRenderer_RenderPawnInternal.Postfix)),
transpiler: new HarmonyMethod(AccessTools.Method(typeof(Patch_ShowHairWithHats), "Transpiler")));
}
}))();
}
catch (TypeLoadException ex) { }
}
}
}
}

View File

@ -0,0 +1,104 @@
using HarmonyLib;
using RimWorld;
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 Rimworld_Animations {
[StaticConstructorOnStartup]
public static class Patch_FacialAnimation {
static Patch_FacialAnimation() {
try {
((Action)(() => {
if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "[NL] Facial Animation - WIP")) {
(new Harmony("rjwanim")).Patch(AccessTools.Method(AccessTools.TypeByName("FacialAnimation.DrawFaceGraphicsComp"), "DrawGraphics"),
prefix: new HarmonyMethod(AccessTools.Method(typeof(Patch_FacialAnimation), "Prefix")));
}
}))();
}
catch (TypeLoadException ex) {
}
}
public static bool Prefix(ref Pawn ___pawn, ref Rot4 headFacing, ref Vector3 headOrigin, ref Quaternion quaternion, ref bool portrait) {
CompBodyAnimator bodyAnim = ___pawn.TryGetComp<CompBodyAnimator>();
if (bodyAnim != null && bodyAnim.isAnimating && !portrait) {
headFacing = bodyAnim.headFacing;
headOrigin = new Vector3(bodyAnim.getPawnHeadPosition().x, headOrigin.y, bodyAnim.getPawnHeadPosition().z);
quaternion = Quaternion.AngleAxis(bodyAnim.headAngle, Vector3.up);
}
return true;
}
/*
public static List<string> rjwLovinDefNames = new List<string>{
"Lovin",
"Quickie",
"GettingQuickie",
"JoinInBed",
"JoinInBedAnimation",
"GettinLovedAnimation",
"GettinLoved",
"GettinLicked",
"GettinSucked",
"GettinRaped",
"ViolateCorpse",
"RJW_Masturbate",
"GettinBred",
"Breed",
"RJW_Mate",
"Bestiality",
"BestialityForFemale",
"StruggleInBondageGear",
"WhoreIsServingVisitors",
"UseFM"
};
public static List<string> rjwRapeDefNames = new List<string> {
"RapeComfortPawn",
"RandomRape",
"RapeEnemy"
};
public static bool Prefix_IsSameA(JobDef job, string ___jobDef, ref bool __result) {
if(___jobDef != null && ___jobDef == "Lovin" && job?.defName != null && rjwLovinDefNames.Contains(job?.defName)) {
__result = true;
return false;
}
else if (___jobDef != null && ___jobDef == "Wait_Combat" && job?.defName != null && rjwRapeDefNames.Contains(job?.defName)) {
__result = true;
return false;
}
return true;
}
public static bool Prefix_IsSameB(string jobName, string ___jobDef, ref bool __result) {
if (___jobDef != null && ___jobDef == "Lovin" && jobName != null && rjwLovinDefNames.Contains(jobName)) {
__result = true;
return false;
}
if (___jobDef != null && ___jobDef == "Wait_Combat" && jobName != null && rjwRapeDefNames.Contains(jobName)) {
__result = true;
return false;
}
return true;
}
*/
}
}

View File

@ -0,0 +1,77 @@
/*using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
using UnityEngine;
using System.Reflection;
using System.Reflection.Emit;
namespace Rimworld_Animations {
public static class HarmonyPatch_HatsDisplaySelection {
public static void PatchHatsDisplaySelectionArgs() {
(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("HatDisplaySelection.Patch"), "DrawHatCEWithHair"),
transpiler: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_HatsDisplaySelection), "ReplaceDrawMeshOrLaterWithAnimate")));
(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("HatDisplaySelection.Patch"), "DrawHatWithHair"),
transpiler: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_HatsDisplaySelection), "ReplaceDrawMeshOrLaterWithAnimate")));
(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("HatDisplaySelection.Patch"), "DrawHeadApparelWithHair"),
prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_HatsDisplaySelection), "PrefixPatchForDrawHeadApparelWithHair")));
}
public static void PrefixPatchForDrawHeadApparelWithHair(PawnRenderer renderer, ref Vector3 rootLoc, ref float angle, bool renderBody, ref Rot4 bodyFacing, ref Rot4 headFacing, RotDrawMode bodyDrawType, bool portrait, bool headStump, bool invisible)
{
PawnGraphicSet graphics = renderer.graphics;
Pawn pawn = graphics.pawn;
CompBodyAnimator bodyAnim = pawn.TryGetComp<CompBodyAnimator>();
if (!graphics.AllResolved)
{
graphics.ResolveAllGraphics();
}
if (bodyAnim != null && bodyAnim.isAnimating && !portrait && pawn.Map == Find.CurrentMap)
{
bodyAnim.tickGraphics(graphics);
bodyAnim.animatePawn(ref rootLoc, ref angle, ref bodyFacing, ref headFacing);
}
}
public static IEnumerable<CodeInstruction> ReplaceDrawMeshOrLaterWithAnimate(IEnumerable<CodeInstruction> instructions) {
MethodInfo drawMeshNowOrLater = AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater");
List<CodeInstruction> codes = instructions.ToList();
for (int i = 0; i < instructions.Count(); i++) {
if (codes[i].
(drawMeshNowOrLater)) {
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(AccessTools.TypeByName("HatDisplaySelection.Patch"), "pawn"));
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), nameof(AnimationUtility.RenderPawnHeadMeshInAnimation), new Type[] { typeof(Mesh), typeof(Vector3), typeof(Quaternion), typeof(Material), typeof(bool), typeof(Pawn) }));
}
else {
yield return codes[i];
}
}
}
}
}
*/

View File

@ -0,0 +1,51 @@
using HarmonyLib;
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 Rimworld_Animations {
[StaticConstructorOnStartup]
public static class Patch_ShowHairWithHats {
static Patch_ShowHairWithHats() {
try {
((Action)(() =>
{
if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "[KV] Show Hair With Hats or Hide All Hats - 1.1")) {
(new Harmony("rjwanim")).Patch(AccessTools.Method(AccessTools.TypeByName("ShowHair.Patch_PawnRenderer_RenderPawnInternal"), "Postfix"), //typeof(ShowHair.Patch_PawnRenderer_RenderPawnInternal), nameof(ShowHair.Patch_PawnRenderer_RenderPawnInternal.Postfix)),
transpiler: new HarmonyMethod(AccessTools.Method(typeof(Patch_ShowHairWithHats), "Transpiler")));
}
}))();
}
catch (TypeLoadException ex) { }
}
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) {
MethodInfo drawMeshNowOrLater = AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater");
List<CodeInstruction> codes = instructions.ToList();
for (int i = 0; i < codes.Count(); i++) {
//Instead of calling drawmeshnoworlater, add pawn to the stack and call my special static method
if (codes[i].OperandIs(drawMeshNowOrLater)) {
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), nameof(AnimationUtility.RenderPawnHeadMeshInAnimation), new Type[] { typeof(Mesh), typeof(Vector3), typeof(Quaternion), typeof(Material), typeof(bool), typeof(Pawn) }));
}
else {
yield return codes[i];
}
}
}
}
}

View File

@ -0,0 +1,25 @@
using HarmonyLib;
using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(JobDriver_Sex), "PlaySexSound")]
class HarmonyPatch_PlaySexSounds
{
public static bool Prefix(JobDriver_Sex __instance)
{
if (__instance.pawn.TryGetComp<CompBodyAnimator>().isAnimating)
{
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,61 @@
using HarmonyLib;
using RimWorld;
using rjw;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using Verse.AI;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(JobDriver_Sex), "SexTick")]
public class HarmonyPatch_SexTick
{
public static bool Prefix(JobDriver_Sex __instance, Pawn pawn, Thing target)
{
if ((target is Pawn) &&
!(
(target as Pawn)?.jobs?.curDriver is JobDriver_SexBaseReciever
&&
((target as Pawn).jobs.curDriver as JobDriver_SexBaseReciever).parteners.Any()
&&
((target as Pawn).jobs.curDriver as JobDriver_SexBaseReciever).parteners[0] == pawn))
{
__instance.ticks_left--;
__instance.sex_ticks--;
__instance.Orgasm();
if (pawn.IsHashIntervalTick(__instance.ticks_between_thrusts))
{
__instance.ChangePsyfocus(pawn, target);
__instance.Animate(pawn, target);
__instance.PlaySexSound();
if (!__instance.Sexprops.isRape)
{
pawn.GainComfortFromCellIfPossible(false);
if (target is Pawn)
{
(target as Pawn).GainComfortFromCellIfPossible(false);
}
}
if(!__instance.isEndytophile)
{
SexUtility.DrawNude(pawn, false);
}
}
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using rjw;
using HarmonyLib;
using Verse;
using RimWorld;
using Verse.AI;
namespace Rimworld_Animations {
/*
[HarmonyPatch(typeof(WorkGiver_Sex), "JobOnThing")]
public static class HarmonyPatch_WorkGiverSex {
public static bool Prefix(ref Job __result, ref Thing t) {
Building_Bed bed = RestUtility.CurrentBed(t as Pawn);
if (bed == null) {
return false;
}
__result = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("JoinInBedAnimation", true), t as Pawn, bed);
return false;
}
}
*/
}

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
using rjw;
using System.Reflection.Emit;
using Verse.AI;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(Bed_Utility), "in_same_bed")]
public static class HarmonyPatch_JobDriver_InSameBedPatch
{
public static bool Prefix(Pawn partner, ref bool __result)
{
if(partner != null && partner.CurJobDef == xxx.casual_sex)
{
__result = true;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(JobDriver_JoinInBed), "MakeNewToils")]
public static class HarmonyPatch_JobDriver_JoinInBed
{
public static void Postfix(JobDriver_JoinInBed __instance, ref IEnumerable<Toil> __result)
{
var toils = __result.ToList();
Toil goToPawnInBed = Toils_Goto.GotoThing(__instance.iTarget, PathEndMode.OnCell);
goToPawnInBed.FailOn(() => !RestUtility.InBed(__instance.Partner) && __instance.Partner.CurJobDef != xxx.gettin_loved && !Bed_Utility.in_same_bed(__instance.Partner, __instance.pawn));
toils[1] = goToPawnInBed;
Toil startPartnerSex = new Toil();
startPartnerSex.initAction = delegate {
if (!(__instance.Partner.jobs.curDriver is JobDriver_SexBaseReciever)) // allows threesomes
{
Job gettinLovedJob = JobMaker.MakeJob(xxx.gettin_loved, __instance.pawn, __instance.Bed); // new gettin loved toil that wakes up the pawn goes here
__instance.Partner.jobs.jobQueue.EnqueueFirst(gettinLovedJob);
__instance.Partner.jobs.EndCurrentJob(JobCondition.InterruptForced);
}
};
toils[2] = startPartnerSex;
toils[3].AddPreTickAction(() =>
{
if (!__instance.Partner.TryGetComp<CompBodyAnimator>().isAnimating)
{
__instance.pawn.TryGetComp<CompBodyAnimator>().isAnimating = false;
}
});
__result = toils.AsEnumerable();
}
}
}

View File

@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
using rjw;
namespace Rimworld_Animations {
[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "Start")]
static class HarmonyPatch_JobDriver_SexBaseInitiator_Start {
public static void Postfix(ref JobDriver_SexBaseInitiator __instance) {
/*
These particular jobs need special code
don't play anim for now
*/
if(__instance is JobDriver_Masturbate || __instance is JobDriver_ViolateCorpse) {
return;
}
if(!AnimationSettings.PlayAnimForNonsexualActs && NonSexualAct(__instance))
{
return;
}
Pawn pawn = __instance.pawn;
Building_Bed bed = __instance.Bed;
if ((__instance.Target as Pawn)?.jobs?.curDriver is JobDriver_SexBaseReciever) {
Pawn Target = __instance.Target as Pawn;
bool quickie = (__instance is JobDriver_SexQuick) && AnimationSettings.fastAnimForQuickie;
int preAnimDuration = __instance.duration;
int AnimationTimeTicks = 0;
if (bed != null) {
RerollAnimations(Target, out AnimationTimeTicks, bed as Thing, __instance.Sexprops.sexType, quickie, sexProps: __instance.Sexprops);
}
else {
RerollAnimations(Target, out AnimationTimeTicks, sexType: __instance.Sexprops.sexType, fastAnimForQuickie: quickie, sexProps: __instance.Sexprops);
}
//Modify Orgasm ticks to only orgasm as many times as RJW stock orgasm allows
if(AnimationTimeTicks != 0)
{
__instance.orgasmstick = preAnimDuration * __instance.orgasmstick / AnimationTimeTicks;
}
}
}
public static void RerollAnimations(Pawn pawn, out int AnimationTimeTicks, Thing bed = null, xxx.rjwSextype sexType = xxx.rjwSextype.None, bool fastAnimForQuickie = false, rjw.SexProps sexProps = null) {
AnimationTimeTicks = 0;
if(pawn == null || !(pawn.jobs?.curDriver is JobDriver_SexBaseReciever)) {
Log.Error("Error: Tried to reroll animations when pawn isn't sexing");
return;
}
List<Pawn> pawnsToAnimate = (pawn.jobs.curDriver as JobDriver_SexBaseReciever).parteners.ToList();
if (!pawnsToAnimate.Contains(pawn)) {
pawnsToAnimate = pawnsToAnimate.Append(pawn).ToList();
}
for(int i = 0; i < pawnsToAnimate.Count; i++) {
if(pawnsToAnimate[i].TryGetComp<CompBodyAnimator>() == null) {
Log.Error("Error: " + pawnsToAnimate[i].Name + " of race " + pawnsToAnimate[i].def.defName + " does not have CompBodyAnimator attached!");
break;
}
}
AnimationDef anim = AnimationUtility.tryFindAnimation(ref pawnsToAnimate, sexType, sexProps);
if (anim != null) {
bool mirror = GenTicks.TicksGame % 2 == 0;
IntVec3 pos = pawn.Position;
for (int i = 0; i < anim.actors.Count; i++)
{
pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().isAnimating = false;
}
for (int i = 0; i < pawnsToAnimate.Count; i++) {
if (bed != null)
pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().setAnchor(bed);
else {
pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().setAnchor(pos);
}
bool shiver = pawnsToAnimate[i].jobs.curDriver is JobDriver_SexBaseRecieverRaped;
pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().StartAnimation(anim, pawnsToAnimate, i, mirror, shiver, fastAnimForQuickie);
int animTicks = anim.animationTimeTicks - (fastAnimForQuickie ? anim.animationStages[0].playTimeTicks : 0);
(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).ticks_left = animTicks;
(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).sex_ticks = animTicks;
(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).duration = animTicks;
AnimationTimeTicks = animTicks;
if(!AnimationSettings.hearts) {
(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).ticks_between_hearts = Int32.MaxValue;
}
}
}
else {
Log.Message("No animation found");
/*
//if pawn isn't already animating,
if (!pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
(pawn.jobs.curDriver as JobDriver_SexBaseReciever).increase_time(duration);
//they'll just do the thrusting anim
}
*/
}
}
static IEnumerable<String> NonSexActRulePackDefNames = new String[]
{
"MutualHandholdingRP",
"MutualMakeoutRP",
};
public static bool NonSexualAct(JobDriver_SexBaseInitiator sexBaseInitiator)
{
if(NonSexActRulePackDefNames.Contains(sexBaseInitiator.Sexprops.rulePack))
{
return true;
}
return false;
}
}
[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "End")]
static class HarmonyPatch_JobDriver_SexBaseInitiator_End {
public static void Postfix(ref JobDriver_SexBaseInitiator __instance) {
if ((__instance.Target as Pawn)?.jobs?.curDriver is JobDriver_SexBaseReciever) {
if (__instance.pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
List<Pawn> parteners = ((__instance.Target as Pawn)?.jobs.curDriver as JobDriver_SexBaseReciever).parteners;
for (int i = 0; i < parteners.Count; i++) {
//prevents pawns who started a new anim from stopping their new anim
if (!((parteners[i].jobs.curDriver as JobDriver_SexBaseInitiator) != null && (parteners[i].jobs.curDriver as JobDriver_SexBaseInitiator).Target != __instance.pawn))
parteners[i].TryGetComp<CompBodyAnimator>().isAnimating = false;
}
__instance.Target.TryGetComp<CompBodyAnimator>().isAnimating = false;
if (xxx.is_human((__instance.Target as Pawn))) {
(__instance.Target as Pawn)?.Drawer.renderer.graphics.ResolveApparelGraphics();
PortraitsCache.SetDirty((__instance.Target as Pawn));
}
}
((__instance.Target as Pawn)?.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Remove(__instance.pawn);
}
if (xxx.is_human(__instance.pawn)) {
__instance.pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
PortraitsCache.SetDirty(__instance.pawn);
}
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
using rjw;
using System.Reflection.Emit;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(JobDriver_SexBaseRecieverLoved), "MakeSexToil")]
public static class HarmonyPatch_JobDriver_SexBaseReceiverLoved
{
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codeInstructions)
{
var ins = codeInstructions.ToList();
for(int i = 0; i < ins.Count; i++)
{
if(i + 13 < ins.Count && ins[i + 13].opcode == OpCodes.Call && ins[i + 13].OperandIs(AccessTools.DeclaredMethod(typeof(Toils_LayDown), "LayDown"))) {
ins.RemoveRange(i, 14);
}
else
{
yield return ins[i];
}
}
}
}
}

View File

@ -0,0 +1,22 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using RimWorld;
using UnityEngine;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(PawnRenderer), "DrawHeadHair")]
public static class HarmonyPatch_HeadHair
{
public static void Prefix(ref Vector3 headOffset, ref float angle)
{
}
}
}

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using RimWorld;
using Verse;
using UnityEngine;
using System.Reflection;
using System.Reflection.Emit;
namespace Rimworld_Animations {
[HarmonyPatch(typeof(PawnRenderer), "RenderPawnInternal", new Type[]
{
typeof(Vector3),
typeof(float),
typeof(bool),
typeof(Rot4),
typeof(RotDrawMode),
typeof(PawnRenderFlags)
}
)]
public static class HarmonyPatch_PawnRenderer
{
[HarmonyBefore(new string[] { "showhair.kv.rw", "erdelf.HumanoidAlienRaces", "Nals.FacialAnimation" })]
public static void Prefix(PawnRenderer __instance, ref Vector3 rootLoc, ref float angle, bool renderBody, ref Rot4 bodyFacing, RotDrawMode bodyDrawType, PawnRenderFlags flags)
{
if (flags.FlagSet(PawnRenderFlags.Portrait)) return;
PawnGraphicSet graphics = __instance.graphics;
Pawn pawn = graphics.pawn;
CompBodyAnimator bodyAnim = pawn.TryGetComp<CompBodyAnimator>();
if (bodyAnim != null && bodyAnim.isAnimating && pawn.Map == Find.CurrentMap)
{
bodyAnim.animatePawnBody(ref rootLoc, ref angle, ref bodyFacing);
}
}
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> ins = instructions.ToList();
for(int i = 0; i < instructions.Count(); i++)
{
if (i - 3 >= 0 && ins[i - 3].opcode == OpCodes.Call && ins[i - 3].operand != null && ins[i - 3].OperandIs(AccessTools.DeclaredMethod(typeof(PawnRenderer), "BaseHeadOffsetAt")))
{
yield return new CodeInstruction(OpCodes.Ldloca, (object)0);
yield return new CodeInstruction(OpCodes.Ldloca, (object)7);
yield return new CodeInstruction(OpCodes.Ldloca, (object)6);
yield return new CodeInstruction(OpCodes.Ldarga, (object)2);
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
yield return new CodeInstruction(OpCodes.Ldarg, (object)6);
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), "AdjustHead"));
yield return ins[i];
//headFacing equals true
}
// Fixes the offsets for eye implants and wounds on the head during animations
else if (ins[i].opcode == OpCodes.Callvirt && ins[i].operand != null && ins[i].OperandIs(AccessTools.DeclaredMethod(typeof(PawnWoundDrawer), "RenderOverBody")))
{
// Pass some additional info to a new overload of RenderOverBody
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
yield return new CodeInstruction(OpCodes.Ldarg_S, (object)6); // renderer flags
yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(PawnWoundDrawerExtension), "RenderOverBody"));
}
else
{
yield return ins[i];
}
}
}
}
}

View File

@ -0,0 +1,29 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
namespace Rimworld_Animations {
[HarmonyPatch(typeof(Thing), "Rotation", MethodType.Getter)]
public static class HarmonyPatch_PawnRotation {
public static bool Prefix(Thing __instance, ref Rot4 __result) {
if(!(__instance is Pawn) || (__instance as Pawn)?.TryGetComp<CompBodyAnimator>() == null || !(__instance as Pawn).TryGetComp<CompBodyAnimator>().isAnimating) {
return true;
}
Pawn pawn = (__instance as Pawn);
__result = pawn.TryGetComp<CompBodyAnimator>().bodyFacing;
return false;
}
}
}

View File

@ -0,0 +1,26 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
namespace Rimworld_Animations {
[HarmonyPatch(typeof(Pawn_DrawTracker), "DrawPos", MethodType.Getter)]
public static class HarmonyPatch_Pawn_DrawTracker {
public static bool Prefix(ref Pawn ___pawn, ref Vector3 __result) {
CompBodyAnimator bodyAnim = ___pawn.TryGetComp<CompBodyAnimator>();
if (bodyAnim != null && bodyAnim.isAnimating) {
__result = ___pawn.TryGetComp<CompBodyAnimator>().anchor + ___pawn.TryGetComp<CompBodyAnimator>().deltaPos;
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,40 @@
using HarmonyLib;
using RimWorld;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(PawnRenderer), "RenderPawnAt")]
public static class PawnRenderer_RenderPawnAt_Patch
{
static bool ClearCache(Pawn pawn)
{
return pawn.IsInvisible() || (pawn.TryGetComp<CompBodyAnimator>() != null && pawn.TryGetComp<CompBodyAnimator>().isAnimating);
}
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
var list = instructions.ToList();
foreach (CodeInstruction i in instructions)
{
if (i.OperandIs(AccessTools.Method(typeof(PawnUtility), "IsInvisible")))
{
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PawnRenderer_RenderPawnAt_Patch), "ClearCache"));
}
else
{
yield return i;
}
}
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using Verse;
namespace Rimworld_Animations
{
[HarmonyPatch(typeof(Thing), "DrawAt")]
public static class HarmonyPatch_Thing
{
public static bool Prefix(Thing __instance)
{
CompThingAnimator thingAnimator = __instance.TryGetComp<CompThingAnimator>();
if (thingAnimator != null && thingAnimator.isAnimating)
{
thingAnimator.AnimateThing(__instance);
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using UnityEngine;
using RimWorld;
namespace Rimworld_Animations {
public class AnimationSettings : ModSettings {
public static bool orgasmQuiver, rapeShiver, soundOverride = true, hearts = true, controlGenitalRotation = false, applySemenOnAnimationOrgasm = false, fastAnimForQuickie = false,
PlayAnimForNonsexualActs = true;
public static bool offsetTab = false, debugMode = false;
public static float shiverIntensity = 2f;
public static Dictionary<string, Vector2> offsets = new Dictionary<string, Vector2>();
public static Dictionary<string, float> rotation = new Dictionary<string, float>();
public override void ExposeData() {
base.ExposeData();
Scribe_Values.Look(ref debugMode, "RJWAnimations-AnimsDebugMode", false);
Scribe_Values.Look(ref offsetTab, "RJWAnimations-EnableOffsetTab", false);
Scribe_Values.Look(ref controlGenitalRotation, "RJWAnimations-controlGenitalRotation", false);
Scribe_Values.Look(ref orgasmQuiver, "RJWAnimations-orgasmQuiver");
Scribe_Values.Look(ref fastAnimForQuickie, "RJWAnimations-fastAnimForQuickie");
Scribe_Values.Look(ref rapeShiver, "RJWAnimations-rapeShiver");
Scribe_Values.Look(ref hearts, "RJWAnimation-sheartsOnLovin");
Scribe_Values.Look(ref PlayAnimForNonsexualActs, "RJWAnims-PlayAnimForNonsexualActs");
Scribe_Values.Look(ref applySemenOnAnimationOrgasm, "RJWAnimations-applySemenOnOrgasm", false);
Scribe_Values.Look(ref soundOverride, "RJWAnimations-rjwAnimSoundOverride", true);
Scribe_Values.Look(ref shiverIntensity, "RJWAnimations-shiverIntensity", 2f);
//todo: save offsetsByDefName
Scribe_Collections.Look(ref offsets, "RJWAnimations-animationOffsets");
Scribe_Collections.Look(ref rotation, "RJWAnimations-rotationOffsets");
//needs to be rewritten
//probably somewhere in options?
}
}
public class RJW_Animations : Mod {
public RJW_Animations(ModContentPack content) : base(content) {
GetSettings<AnimationSettings>();
}
public override void DoSettingsWindowContents(Rect inRect) {
Listing_Standard listingStandard = new Listing_Standard();
listingStandard.Begin(inRect);
listingStandard.CheckboxLabeled("Enable Sound Override", ref AnimationSettings.soundOverride);
listingStandard.CheckboxLabeled("Control Genital Rotation", ref AnimationSettings.controlGenitalRotation);
listingStandard.CheckboxLabeled("Play Fast Animation for Quickie", ref AnimationSettings.fastAnimForQuickie);
listingStandard.CheckboxLabeled("Apply Semen on Animation Orgasm", ref AnimationSettings.applySemenOnAnimationOrgasm);
if(AnimationSettings.applySemenOnAnimationOrgasm) {
listingStandard.Label("Recommended--turn down \"Cum on body percent\" in RJW settings to about 33%");
}
listingStandard.CheckboxLabeled("Enable Orgasm Quiver", ref AnimationSettings.orgasmQuiver);
listingStandard.CheckboxLabeled("Enable Rape Shiver", ref AnimationSettings.rapeShiver);
listingStandard.CheckboxLabeled("Enable hearts during lovin'", ref AnimationSettings.hearts);
listingStandard.CheckboxLabeled("Play animation for nonsexual acts (handholding, makeout)", ref AnimationSettings.PlayAnimForNonsexualActs);
listingStandard.CheckboxLabeled("Enable Animation Manager Tab", ref AnimationSettings.offsetTab);
listingStandard.Label("Shiver/Quiver Intensity (default 2): " + AnimationSettings.shiverIntensity);
AnimationSettings.shiverIntensity = listingStandard.Slider(AnimationSettings.shiverIntensity, 0.0f, 12f);
listingStandard.CheckboxLabeled("Debug Mode", ref AnimationSettings.debugMode);
listingStandard.End();
base.DoSettingsWindowContents(inRect);
}
public override void WriteSettings() {
base.WriteSettings();
OffsetMainButtonDefOf.OffsetManager.buttonVisible = AnimationSettings.offsetTab;
}
public override string SettingsCategory() {
return "RJW Animation Settings";
}
}
}

View File

@ -0,0 +1,319 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using rjw.Modules.Interactions.Helpers;
using rjw.Modules.Interactions.Objects;
using UnityEngine;
using Verse;
using Verse.AI;
using rjw.Modules.Interactions.Enums;
namespace Rimworld_Animations {
public static class AnimationUtility {
/*
Note: always make the list in this order:
Female pawns, animal female pawns, male pawns, animal male pawns
*/
public static AnimationDef tryFindAnimation(ref List<Pawn> participants, rjw.xxx.rjwSextype sexType = 0, rjw.SexProps sexProps = null) {
InteractionWithExtension interaction = InteractionHelper.GetWithExtension(sexProps.dictionaryKey);
if(interaction.HasInteractionTag(InteractionTag.Reverse))
{
Pawn buffer = participants[1];
participants[1] = participants[0];
participants[0] = buffer;
}
participants =
participants.OrderBy(p => p.jobs.curDriver is rjw.JobDriver_SexBaseInitiator)
.OrderBy(p => rjw.xxx.can_fuck(p))
.ToList();
List<Pawn> localParticipants = new List<Pawn>(participants);
IEnumerable<AnimationDef> options = DefDatabase<AnimationDef>.AllDefs.Where((AnimationDef x) => {
if (x.actors.Count != localParticipants.Count) {
return false;
}
for (int i = 0; i < x.actors.Count; i++) {
if (rjw.RJWPreferenceSettings.Malesex == rjw.RJWPreferenceSettings.AllowedSex.Nohomo) {
if (rjw.xxx.is_male(localParticipants[i]) && x.actors[i].isFucked) {
return false;
}
}
if (x.actors[i].requiredGender != null && !x.actors[i].requiredGender.Contains(localParticipants[i].gender.ToStringSafe<Gender>()))
{
if (AnimationSettings.debugMode)
{
Log.Message(string.Concat(new string[]
{
x.defName.ToStringSafe<string>(),
" not selected -- ",
localParticipants[i].def.defName.ToStringSafe<string>(),
" ",
localParticipants[i].Name.ToStringSafe<Name>(),
" does not match required gender"
}));
}
return false;
}
if ((x.actors[i].blacklistedRaces != null) && x.actors[i].blacklistedRaces.Contains(localParticipants[i].def.defName)) {
if(AnimationSettings.debugMode)
Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " is blacklisted");
return false;
}
if(x.actors[i].defNames.Contains("Human")) {
if (!rjw.xxx.is_human(localParticipants[i])) {
if (AnimationSettings.debugMode)
Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " is not human");
return false;
}
}
else if (!x.actors[i].bodyDefTypes.Contains(localParticipants[i].RaceProps.body)) {
if (!x.actors[i].defNames.Contains(localParticipants[i].def.defName)) {
if (rjw.RJWSettings.DevMode) {
string animInfo = x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " is not ";
foreach(String defname in x.actors[i].defNames) {
animInfo += defname + ", ";
}
if (AnimationSettings.debugMode)
Log.Message(animInfo);
}
return false;
}
}
//genitals checking
if(!GenitalCheckForPawn(x.actors[i].requiredGenitals, localParticipants[i], out string failReason)) {
Debug.Log("Didn't select " + x.defName + ", " + localParticipants[i].Name + " " + failReason);
return false;
}
//TESTING ANIMATIONS ONLY REMEMBER TO COMMENT OUT BEFORE PUSH
/*
if (x.defName != "Cunnilingus")
return false;
*/
if (x.actors[i].isFucking && !rjw.xxx.can_fuck(localParticipants[i])) {
if (AnimationSettings.debugMode)
Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " can't fuck");
return false;
}
if (x.actors[i].isFucked && !rjw.xxx.can_be_fucked(localParticipants[i])) {
if (AnimationSettings.debugMode)
Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " can't be fucked");
return false;
}
}
return true;
});
List<AnimationDef> optionsWithInteractionType = options.ToList().FindAll(x => x.interactionDefTypes != null && x.interactionDefTypes.Contains(sexProps.sexType.ToStringSafe()));
if (optionsWithInteractionType.Any()) {
if (AnimationSettings.debugMode)
Log.Message("Selecting animation for interaction type " + sexProps.sexType.ToStringSafe() + "...");
return optionsWithInteractionType.RandomElement();
}
List<AnimationDef> optionsWithSexType = options.ToList().FindAll(x => x.sexTypes != null && x.sexTypes.Contains(sexType));
if (optionsWithSexType.Any()) {
if (AnimationSettings.debugMode)
Log.Message("Selecting animation for rjwSexType " + sexType.ToStringSafe() + "...");
return optionsWithSexType.RandomElement();
}
/*
if(optionsWithInitiator.Any()) {
if (AnimationSettings.debugMode)
Log.Message("Selecting animation for initiators...");
}
*/
if (options != null && options.Any()) {
if (AnimationSettings.debugMode)
Log.Message("Randomly selecting animation...");
return options.RandomElement();
}
else
return null;
}
public static void RenderPawnHeadMeshInAnimation1(Mesh mesh, Vector3 loc, Quaternion quaternion, Material material, bool drawNow, Pawn pawn) {
if (pawn == null || pawn.Map != Find.CurrentMap) {
GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, drawNow);
return;
}
CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
if (pawnAnimator == null || !pawnAnimator.isAnimating) {
GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, drawNow);
} else {
Vector3 pawnHeadPosition = pawnAnimator.getPawnHeadPosition();
pawnHeadPosition.y = loc.y;
GenDraw.DrawMeshNowOrLater(MeshPool.humanlikeHeadSet.MeshAt(pawnAnimator.headFacing), pawnHeadPosition, Quaternion.AngleAxis(pawnAnimator.headAngle, Vector3.up), material, true);
}
}
public static void AdjustHead(ref Quaternion quat, ref Rot4 bodyFacing, ref Vector3 pos, ref float angle, Pawn pawn, PawnRenderFlags flags)
{
if (flags.FlagSet(PawnRenderFlags.Portrait)) return;
CompBodyAnimator anim = pawn.TryGetComp<CompBodyAnimator>();
if (anim.isAnimating)
{
bodyFacing = anim.headFacing;
angle = anim.headAngle;
quat = Quaternion.AngleAxis(anim.headAngle, Vector3.up);
pos = anim.getPawnHeadOffset();
}
}
public static void RenderPawnHeadMeshInAnimation(Mesh mesh, Vector3 loc, Quaternion quaternion, Material material, bool portrait, Pawn pawn, float bodySizeFactor = 1) {
if (pawn == null) {
GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, portrait);
return;
}
CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
if (pawnAnimator == null || !pawnAnimator.isAnimating || portrait) {
GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, portrait);
}
else {
Vector3 pawnHeadPosition = pawnAnimator.getPawnHeadPosition();
pawnHeadPosition.x *= bodySizeFactor;
pawnHeadPosition.x *= bodySizeFactor;
pawnHeadPosition.y = loc.y;
GenDraw.DrawMeshNowOrLater(mesh, pawnHeadPosition, Quaternion.AngleAxis(pawnAnimator.headAngle, Vector3.up), material, portrait);
}
}
public static bool GenitalCheckForPawn(List<string> requiredGenitals, Pawn pawn, out string failReason) {
failReason = null;
if (requiredGenitals != null) {
if (requiredGenitals.Contains("Vagina")) {
if (!rjw.Genital_Helper.has_vagina(pawn)) {
failReason = "missing vagina";
return false;
}
}
if (requiredGenitals.Contains("Penis")) {
if (!(rjw.Genital_Helper.has_multipenis(pawn) || rjw.Genital_Helper.has_penis_infertile(pawn) || rjw.Genital_Helper.has_penis_fertile(pawn) || rjw.Genital_Helper.has_ovipositorM(pawn) || rjw.Genital_Helper.has_ovipositorF(pawn))) {
failReason = "missing penis";
return false;
}
}
if (requiredGenitals.Contains("Mouth")) {
if (!rjw.Genital_Helper.has_mouth(pawn)) {
failReason = "missing mouth";
return false;
}
}
if (requiredGenitals.Contains("Anus")) {
if (!rjw.Genital_Helper.has_anus(pawn)) {
failReason = "missing anus";
return false;
}
}
if (requiredGenitals.Contains("Breasts")) {
if (!rjw.Genital_Helper.can_do_breastjob(pawn)) {
failReason = "missing breasts";
return false;
}
}
if (requiredGenitals.Contains("NoVagina")) {
if (rjw.Genital_Helper.has_vagina(pawn)) {
failReason = "has vagina";
return false;
}
}
if (requiredGenitals.Contains("NoPenis")) {
if ((rjw.Genital_Helper.has_multipenis(pawn) || rjw.Genital_Helper.has_penis_infertile(pawn) || rjw.Genital_Helper.has_penis_fertile(pawn))) {
failReason = "has penis";
return false;
}
}
if (requiredGenitals.Contains("NoMouth")) {
if (rjw.Genital_Helper.has_mouth(pawn)) {
failReason = "has mouth";
return false;
}
}
if (requiredGenitals.Contains("NoAnus")) {
if (rjw.Genital_Helper.has_anus(pawn)) {
failReason = "has anus";
return false;
}
}
if (requiredGenitals.Contains("NoBreasts")) {
if (rjw.Genital_Helper.can_do_breastjob(pawn)) {
failReason = "has breasts";
return false;
}
}
}
return true;
}
public static Rot4 PawnHeadRotInAnimation(Pawn pawn, Rot4 regularPos)
{
Debug.Log("Test");
if(pawn?.TryGetComp<CompBodyAnimator>() != null && pawn.TryGetComp<CompBodyAnimator>().isAnimating)
{
return pawn.TryGetComp<CompBodyAnimator>().headFacing;
}
return regularPos;
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Verse;
namespace Rimworld_Animations
{
public class PatchOperationAddOrReplace : PatchOperationPathed
{
protected string key;
private XmlContainer value;
protected override bool ApplyWorker(XmlDocument xml)
{
XmlNode valNode = value.node;
bool result = false;
IEnumerator enumerator = xml.SelectNodes(xpath).GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object obj = enumerator.Current;
result = true;
XmlNode parentNode = obj as XmlNode;
XmlNode xmlNode = parentNode.SelectSingleNode(key);
if (xmlNode == null)
{
// Add - Add node if not existing
xmlNode = parentNode.OwnerDocument.CreateElement(key);
parentNode.AppendChild(xmlNode);
}
else
{
// Replace - Clear existing children
xmlNode.RemoveAll();
}
// (Re)add value
xmlNode.AppendChild(parentNode.OwnerDocument.ImportNode(valNode.FirstChild, true));
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
return result;
}
}
}

BIN
1.4/Textures/UI/MainTab.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -16,5 +16,13 @@
<li IfModActive="c0ffee.SexToysMasturbation">Patch_SexToysMasturbation</li>
<li IfModActive="c0ffee.SexToysMasturbation">Patch_SexToysMasturbation/1.3</li>
</v1.3>
<v1.3>
<li>/</li>
<li>1.4</li>
<li IfModActive="velc.HatsDisplaySelection">Patch_HatsDisplaySelection/1.2</li>
<li IfModActive="c0ffee.SexToysMasturbation">Patch_SexToysMasturbation</li>
<li IfModActive="c0ffee.SexToysMasturbation">Patch_SexToysMasturbation/1.3</li>
</v1.3>
</loadFolders>