Ludeon Forums

Ludeon Forums

  • August 09, 2020, 04:47:52 AM
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - JT

Pages: [1] 2 3 ... 9
1
A lot of the weather stuff is indeed hard-coded to use Unity assets instead of external files -- take a look at your favourite IL decompiler at Weather or Snow for instance, and you'll see that the particles are all loaded as Unity materials rather than loaded as Texture2Ds from mod data (which would enable easy modding).  That said, it wouldn't be completely unapproachable to make a mod with an assembly that simply edits the Material contained in the target reference class, since even though they are private accessible, you could always use Harmony to replace them with a runtime-generated Material of your choice.  For example, the vanilla RimWorld snow gentle weather is:

Code: [Select]
[StaticConstructorOnStartup]
public class WeatherOverlay_SnowGentle : SkyOverlay
{
private static readonly Material SnowGentleOverlayWorld = MatLoader.LoadMat("Weather/SnowOverlayWorld");

public WeatherOverlay_SnowGentle()
{
worldOverlayMat = SnowGentleOverlayWorld;
worldOverlayPanSpeed1 = 0.002f;
worldPanDir1 = new Vector2(-0.25f, -1f);
worldPanDir1.Normalize();
worldOverlayPanSpeed2 = 0.003f;
worldPanDir2 = new Vector2(-0.24f, -1f);
worldPanDir2.Normalize();
}
}

You could Harmony-postfix the WeatherOverlay_SnowGentle constructor (see "Target method annotations" on the Github page for how to target a constructor) by overriding the worldOverlayMat with a newly generated Material of your own.  Since Unity is really really big on its WYSIWYG editor and assorted nonsense, a simple operation like loading a PNG from the disk at runtime, converting it to a texture, and popping it into SetTexture() as byte data, is absurdly difficult compared to most games -- but still should be doable.

2
Releases / Re: [R1.0] Signs and Memorials (v1.2.3)
« on: March 07, 2020, 07:35:07 PM »
Howdy y'all!

I went ahead and forked this, fixed this, and ported this, because it was causing save corruption on the 1.0 version and the fix contributed by the author last September missed the underlying cause of the error.  (Anyone who knows me knows that I will sooner allow a project to fester and die than to roll back scope.  It's the reason why I have left behind a litany of vapourware...)

Long story short, I grew up in a-- I mean, a fixed 1.0 version and a 1.1 port can be downloaded directly from https://github.com/jtgibson01/RimWorld-Signs_and_Memorials

1.1 has a few memorials now.  I haven't ported the features of this mod onto vanilla memorials.  Yes, it's less relevant in 1.1 -- but then, I only ported for the benefit of 1.0 anyway, and a port-up to 1.1 was mostly an afterthought. ;-)  The upgrade has also been offered to the original author's repository as a pull request, since I have little or no intention of maintaining this.  Anyone else can pick up the ball anytime they like. =)

3
Releases / Re: [1.0] Simple Slavery
« on: July 22, 2019, 07:07:15 PM »
@Ziehn: https://github.com/Aviuz/PrisonLabor/pull/144

If that pull request goes through, it should be possible to support Prison Labor motivation mechanics out of the box!

Simple Slavery's own support is almost as simple.  You'd have to build against PrisonLabor.dll, though, but it is a soft requirement.  The alternative would be to use Reflection, but Reflection is inefficient and obnoxious.

Hediffs.cs
Code: [Select]
// Freedom!!!
public void TryToEscape()
{
isMovingToEscape = false; // We've moved into place to escape already
hoursSinceLastEscapeAttempt = 0; // Reset time tracker
SaveMemory (); // Save our work priorities and willpower to the external hediff
Messages.Message ("MessageSlaveEscaping".Translate(pawn.Name.ToStringShort), pawn, MessageTypeDefOf.ThreatBig); //Z- NameStringShort -> Name.ToStringShort
//Z- Added Letter to escaping slaves event
string text = "LetterIncidentSlaveEscaping".Translate(pawn.Name.ToString());
Find.LetterStack.ReceiveLetter("LetterLabelSlaveEscaping".Translate(), text, LetterDefOf.NegativeEvent, null);
pawn.SetFaction (actualFaction); // Revert to real faction
pawn.guest.SetGuestStatus (slaverFaction, true);
pawn.guest.Released = false; // Ensure the slave is not set to released mode
pawn.guest.interactionMode = PrisonerInteractionModeDefOf.NoInteraction; // Ensure the interaction mode is not "release"
pawn.guilt.Notify_Guilty();

#if PRISONLABOR
//Prison Labor support
Need escape = pawn.needs.TryGetNeed(DefDatabase<NeedDef>.GetNamed("PrisonLabor_Motivation"));
if(escape != null) {
PrisonLabor.Need_Motivation need = (PrisonLabor.Need_Motivation)escape;
need.Inspired = false;
need.CurLevel = 0f;
need.CanEscape = true;
need.ReadyToRun = true;
}
#endif
}

4
With regards to ammunition damage, it's true; there is a certain strangeness to how all cartridge types behave the same way when used in different weapons.

CE supports ammo types providing weapon-specific projectile stats. It's not used in the base mod as vanilla/CE Guns don't have any weapons where the difference would be significant. If some third-party mod does and isn't using this functionality then that's on whoever patched it.

Is there some other way to do this than defining an entirely new AmmoSet (and series of BulletCEs), though?  It's simple and easy to define a series of new AmmoSets for an entirely new ammo type added by the mod (I've done that myself for my WIP CE compatibility patch for Metro Armory), but duplicating a core AmmoSet feels particularly wrong.

Giving the weapon a stat multiplier would be more cross-compatible than creating patch soup where a mod must duplicate a vanilla AmmoSet for itself, and then not be able to use any ammo types that are patched into the vanilla AmmoSet by other mods other than by having to check for those mods and patch itself, and/or demand those mods to patch for its benefit.

A simple DamageFactor and MuzzleVelocityFactor as part of the weapon's stats would work wonders: the DamageFactor would increase (or decrease) the damage of each projectile fired by that weapon, and the MuzzleVelocityFactor would increase (or decrease) the speed.

(In case you're wondering, I already have two as-yet-unreleased use cases where I've bumped into this barrier:
1) Adding new low-tech variants of hand-swaged Soviet bullets that can be made by tribals, which are patched into vanilla 5.45x39mm and 7.62x54mm lists.  This invalidates any duplicates of the vanilla AmmoSet unless they accommodate this patch too.
2) Adding various AmmoSets to tweak the draw strengths of the bows I use in my mod, such that arrows, crossbow bolts, streamlined arrows, and great arrows all inflict different amounts of damage depending on the bow type.  Any arrow added to the vanilla AmmoSet is not duplicated into the new AmmoSets.)

5
Just noticed this yesterday. More Than Capable/your fork solves the Prison Labor incompatibility -- I can now assign pawns to hated labour as before! Thanks notfood!

6
Releases / Re: [1.0] Lulu's Loony Levities (updated 2019-07-13)
« on: July 13, 2019, 03:05:12 PM »
"Disorder". n. A condition which causes harm to others, and/or harm or distress to the person who has it.
"Autism". n. (uncountable) A personality type that is audaciously called a disorder by those without autism.


Ahem. =)

Organ Cloning and Bones and Chitin definitely seem like things I'm interested in.  Good show!

(Bones & Chitin in particular, since Rim of Madness/Call of Cthulhu Bones is just excessively over-the-top.  The entire production chain related to bones was almost silly, and the twentieth shrine made out of calcium concrete that I ran into was enough to drop the "eff it, I'm out" bomb.  But I loved the part of the mod that was actually about bones. ;-))

7
Is there a mod that makes boomalopes give chemfuel rather than FSX (or makes them give both?)  I love this mod, but I like having my boomalopes usable as a fuel supply for my generators.

I've always used Chemicals & Neutroamine for the neutroglycerin, which is then refined at the Core biofuel refinery into chemfuel.  The Steam thread seems to suggest it conflicts, but I had the opposite problem when SparklingWorlds and Chemicals & Neutroamine would produce both neutroglycerin types from the same animal.  I tend not to bother with high-level spacer play (tribals are way more fun for me, and don't tend to attract mechanoids either) so I can't actually confirm, but I'll test it out now and see.

I'm a hopeless self-interested utilitarian when it comes to helping others, but since this problem will (eventually) affect me too, I'll throw a patch up when/if I confirm it's a problem. ;-)

[edit] Actually, I think you're already covered, come to think of it.  Try using Chemicals & Neutroamine together with N7Huntman's Combat Extended: Distilling.

[edit2] And now double-checked, both neutroglycerin and FSX produce naturally from the boomalope.  Both are labelled as "chemical fullness", which is probably why the other fellow on the C&N thread was confused.

8
Releases / Re: [1.0] XND's RimWorld Mods - Updated 2019-07-12
« on: July 13, 2019, 01:32:56 PM »
Wow, the carpenter's bench looks great!  It's hilarious in hindsight that no one thought to do this before, since building furniture before placing it has been a staple of Dwarf Fortress since forever.

It wouldn't be too tough to make a custom disassemble bill that takes any minified furniture item with a thingFilter.  You'd still need a custom RecipeWorkerCounter class to handle the job, but most of it could still be handled in vanilla.  With the thing filter, the player could specify the quality ranges of furniture to deconstruct -- so if she doesn't want Poor or worse, she would just set the quality range of her "disassemble" bill to Awful~Poor, etc.  The only tricky-dicky part is pulling the ThingOwner from the minified thing, but thankfully even that's already stored in the innerContainer field.

[edit] Couple minor tweaks, took forever to re-find "RecipeWorkerCounter" in ILSpy. =P

9
Yeesh, I hate that I keep missing these replies.

I still have 15+ minute load times in the new version.  Better Loading, RIMMSLoadUp, and ModCheck don't solve the problem.  Granted, I have a few mods in my now-319-mod load order that have rather questionable source code -- SeedsPlease does some chaotic stuff, for instance, that it really shouldn't.  That said, I've been working on several mods fairly religiously since mid-June!  Field Surgery is more or less OK for release, but I haven't done a full testing phase yet.

Here's the changelog as a teaser for now (note my rather incorrect estimate on when I figured the release date would be):
01 July 2019 - 1.0 Version 5
* Updated to 1.0, finally.  (There's that qualifier again...)
* Happy effin' Canada Day, eh?

* Fixed bug with XML missing products for production recipes in release version.  Bug had been already fixed in dev version even before I released the release version... sigh. (Exoray)
* Fixed bug with XML linked to wrong class for plasma extraction recipe and saline administration.  Dev version had this bug, too -- oops. (mimib14)
* Incorporated LocalDefOf tweak from HardcoreSK fork to avoid RimWorld locating and referencing defs at runtime (much more elegant). (sidfu)
* Actually included the ability to drink blood in desperation, even though I had added the thoughts -- could've sworn I had done this already, but even the dev version was missing it.  Maybe I edited it into the A16 version by mistake?  In any case... sigh. (via sidfu)
* Patch added for Cupro's Drinks (dismar's update) which will sort jinnantonyx and tonic water into its drinks categories.
* Nerfed antimalarial Blood Pumping penalty from -10% to -2% (Blood Pumping affects everything including Manipulation and Moving, which was a far worse penalty than intended); starts at -5% for the initial few moments
* Endotide now injects faster and plays appropriate sound effects.
* Fixed missing endotide JoyKind.  I missed this because another mod overwrote vanilla abstracts.  (Bad, bad, Children &amp; Pregnancy!)
* Tweaked thingfilters for plasma pack and saline pack surgical bills for better compatibility with Dub's Mint Menus.
* Endotide now causes total heart failure when multiple shots are injected.  As an overdosing person falls unconscious long before this, it would require someone else to do this.  In other words, the polar opposite of the mod's initial feature (amputating without anaesthetic) has been added...
* A specific surgical bill now specifically allows you to elect to use too much anaesthetic, to put your patient to a painless death.  It requires either six units of any medicine (for painkillers), or three units of endotide (more powerful, more specific).  This is instantaneous, even if using Death Rattle (the above is not).
* Mod Settings menu is now available!
** Disable elective dismemberment entirely.
** Disable freeze degradation for blood packs (currently does not alter/remove freezable blood packs).
** Disable torture thoughts independently for prisoner, surgeon, and/or your colonists.
** Configure how angry the target faction will get when you torture/execute one of their actors.

Nothing really impressive other than basic maintenance and balance, although I'm pretty happy with the Mod Settings menu (UI design is NOT my field of expertise).  A lot of work has gone into mapping out vanilla code for Harmony patches, for a rather large expansion to features that I'd like to tackle after I've gotten the official update done, but (like almost everything I ever do) I wound up getting so excited over the potential that I started doing the work before I'd gotten the official update done.

10
Releases / Re: [1.0] Giddy-up! - updated June 27
« on: July 03, 2019, 09:53:09 AM »
Everything up to date, this happens when I try to designate a no-riding zone:
[spoiler]
at CleaningPriority.ListerFilthInAreas_MapComponent.OnAreaChange (Verse.IntVec3,bool,Verse.Area) <0x000c5>
[/spoiler]

And this happens when I try to put one of the mount drop spots, with the difference that it actually places the spot, while the no ride area is not being "constructed":

[spoiler]
at CleaningPriority.ListerFilthInAreas_MapComponent.OnAreaChange (Verse.IntVec3,bool,Verse.Area) <0x000c5>
[/spoiler]

Although Giddy-Up is deeper in the call stack, the cause of the crash is Cleaning Priority (or whichever other Harmony mod is patching the Verse.Area), which does not seem prepared to handle the area designations it doesn't recognise.

Since the source code for Cleaning Priority seems to be trying to catch null keys, Cleaning Priority will need to add some debugging information to decipher what exactly is occurring before it can be fixed.  Giddy-Up, being so much higher up the call stack, can't do much to solve this problem.

In the meantime, you can call it a straight incompatibility with Cleaning Priority. =)

11
Unfinished / Re: [1.0] (WIP) Project Red Horse: Tacticool Expansion
« on: June 27, 2019, 09:39:23 AM »
A lot of the stuff in FastTrack could be accomplished entirely by XML patch and pushed to CE master or kept as an addon mod, rather than having to edit CE master files. =)

For instance, adding the RH MSF TranqNonLethal AmmoCategoryDef to AmmoCategories_Advanced.xml could be done with a patch like (not tested, literally just written from my memory of the patch format):

Code: [Select]
<Patch>
<Operation Class="PatchOperationFindMod">
<mods>
<li>(Combat Extended's mod name from About.xml)</li>
</mods>
<match Class="PatchOperationFindMod">
<mods>
<li>(Project Red Horse MSF's mod name from About.xml</li>
</mods>
<match Class="PatchOperationSequence">
<operations>
<li Class="PatchOperationTest"> <!-- Find file that contains Charged ammo (AmmoCategories_Advanced.xml) -->
<xpath>Defs/CombatExtended.AmmoCategoryDef[defName="Charged"]</xpath>
</li>
<li Class="PatchOperationAdd"> <!-- Adds the new AmmoCategory def to the same file, under the root Defs node -->
<xpath>Defs</xpath>
<value>
<CombatExtended.AmmoCategoryDef>
<defName>TranqNonLethal</defName>
<label>tranquilizer</label>
<description>Special round designed for non-lethal engagements of targets. Filled with fast-acting sedatives and tipped with a hypodermic needle.</description>
</CombatExtended.AmmoCategoryDef>
</value>
</li>
</operations>
</match>
</match>
</Operation>
</Patch>

12
I've made a couple tweaks to Rational Romance, which I heartily recommend incorporating into the official distribution.  I've tested it locally and it works wonderfully.

1) Nuked the stray "at < 0" devmode log warning, which cannot trigger during the vanilla game, but triggers frequently when using Children & Pregnancy and/or Atlas' Android Tiers.  Since outlanders and tribals can all generate children, this warning would appear frequently during world generation, during caravan arrivals, and during new game start when a child is included in the starting pawns, which is a source of annoyance when running dev mode.

2) Since DoesTargetPawnAcceptAdvance() duplicated the exact same conditions as IsTargetPawnFreeForHookup(), I simply converted the massive list of conditions to call IsTargetPawnFreeForHookup(), since I was editing that line anyway.  Much more concise and easier to maintain.

3) Corrected the silliness where two pawns would repeatedly try hooking up with each other and rejecting each other, literally standing in front of each other spamming hookup requests with each other.  ("I want to make love.  Want to make love to me?"  "No, but I want to make love.  Want to make love to me?"  "No, but I want to make love.  Want to make love to me?" ...Guys.  Seriously.  Figure it out.)  Now, if one has tried hooking up with the other within recent memory (2.5 minutes/9000 ticks), and the other now asks the first one to hook up, that will be interpreted as changing their mind, causing an auto-accept.

4) Similarly, if the target pawn is also on a hookup job when the first one asks, it will be auto-accepted.  Since it was easier than creating and navigating a massive cast-and-dereference chain to find out who the target pawn was actually trying to hook up with, I just assume that it's like a Tinder date and they're no longer concerned about who they hook up with, so long as the other pawn is at least barely appealing to them (>=10% attraction).  "He may not be Mr. Right, but he's Mr. Right Here and Mr. Right Now."

5) Introduces a cooldown to the hookup joygiver and job driver based on whether the target pawn has already said no.  It does so by scanning for the rebuffed-hookup thought and checking to see that the rebuff happened recently.  If so, that pawn is off limits and the job won't be produced at all for that pawn.  If, however, the thought still exists but is reasonably "old" (10800 ticks, or 3 minutes), they might try again.  This stops the worst cases where the pawn will try over and over and over again after every other job -- or even try non-stop -- to hook up, although it doesn't catch the rare edge case where the pawns are working on opposite sides of the map and will travel back and forth to try hooking up.  I chose 3 minutes after some careful thought: if much longer, the rebuff penalties and opinion penalties wouldn't be able to stack up; if only a little longer, the pawns will fall into joy deprivation too easily.

(The same cooldown tweak could also be applied to the date system, but I haven't yet had a colony with datespam that would work as a test case.  I have however had a colony with massive hookup spam. =P)

6) Finally, it makes joy-deprived pawns more likely to accept a hookup request, because if their joy is getting that low at all, romantic joy is probably their only option for entertainment.  A pawn with an Empty joy meter will auto-accept if attraction >= 10%, and a pawn with Low or Very Low joy will scale upward from equally likely at joy 30%, down to 3 times more likely at joy 10%, and 30 times more likely at joy 1% (which is why 0%/Empty is simply an auto-accept).

Source code file, with plenty of my irreverent humour.  Since the licence provided in About.xml only applies to modpacks, I'm not certain what my distribution rights are, so I'm sharing-alike the source code only for now.
udiff:
Code: [Select]
--- E:/Games/Rimworld/1.0/RF - Rational Romance/Source/Rainbeau's Rational Romance/MyClass.cs Thu Nov 15 18:44:20 2018
+++ E:/Games/Rimworld/Homemade/RationalRomance/HookupCooldown/MyClass.cs Thu Jun 27 05:12:45 2019
@@ -831,7 +831,7 @@
  private static float MinPossibleAgeGapAtMinAgeToGenerateAsLovers(Pawn p1, Pawn p2) {
  float ageChronologicalYearsFloat = p1.ageTracker.AgeChronologicalYearsFloat - 14f;
  if (ageChronologicalYearsFloat < 0f) {
- Log.Warning("at < 0", false);
+ //Log.Warning("at < 0", false);
  return 0f;
  }
  float single = PawnRelationUtility.MaxPossibleBioAgeAt(p2.ageTracker.AgeBiologicalYearsFloat, p2.ageTracker.AgeChronologicalYearsFloat, ageChronologicalYearsFloat);
@@ -1230,6 +1230,7 @@
  public override bool TryMakePreToilReservations(bool errorOnFailed) {
  return true;
  }
+
  public bool successfulPass = true;
  public bool wasSuccessfulPass {
  get { return this.successfulPass; }
@@ -1249,14 +1250,32 @@
  private TargetIndex TargetBedIndex {
  get { return TargetIndex.B; }
  }
+
+ //NEW: If TargetPawn had just recently asked for a hookup (in last 2.5 minutes) and was rebuffed by the Actor,
+ // but the Actor is now asking the TargetPawn instead, that means the Actor changed theirmind and the
+ // TargetPawn will auto-accept (we can presume they still want a go if they asked so recently in reverse).
+ //The TargetPawn still keeps the rebuffed thought (the Actor shouldn't be such a !&$%ing tease).
  private bool DoesTargetPawnAcceptAdvance() {
- return !PawnUtility.WillSoonHaveBasicNeed(this.TargetPawn) && !PawnUtility.EnemiesAreNearby(this.TargetPawn, 9, false) && this.TargetPawn.jobs.curJob.def != JobDefOf.LayDown && this.TargetPawn.jobs.curJob.def != JobDefOf.BeatFire && this.TargetPawn.jobs.curJob.def != JobDefOf.Arrest && this.TargetPawn.jobs.curJob.def != JobDefOf.Capture && this.TargetPawn.jobs.curJob.def != JobDefOf.EscortPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.ExtinguishSelf && this.TargetPawn.jobs.curJob.def != JobDefOf.FleeAndCower && this.TargetPawn.jobs.curJob.def != JobDefOf.MarryAdjacentPawn && this.TargetPawn.jobs.curJob.def != JobDefOf.PrisonerExecution && this.TargetPawn.jobs.curJob.def != JobDefOf.ReleasePrisoner && this.TargetPawn.jobs.curJob.def != JobDefOf.Rescue && this.TargetPawn.jobs.curJob.def != JobDefOf.SocialFight && this.TargetPawn.jobs.curJob.def != JobDefOf.SpectateCeremony && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeToBedToOperate && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeWoundedPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.UseCommsConsole && this.TargetPawn.jobs.curJob.def != JobDefOf.Vomit && this.TargetPawn.jobs.curJob.def != JobDefOf.Wait_Downed && SexualityUtilities.WillPawnTryHookup(this.TargetPawn) && SexualityUtilities.IsHookupAppealing(this.TargetPawn, base.GetActor());
+ return IsTargetPawnFreeForHookup() &&
+ SexualityUtilities.WillPawnTryHookup(this.TargetPawn) &&
+ (
+ SexualityUtilities.IsHookupAppealing(this.TargetPawn, base.GetActor()) ||
+ this.TargetPawn.needs.mood.thoughts.memories.Memories.Any(x => SexualityUtilities.IsRebuffedHookupThought(x, base.GetActor(), 9000))
+ );
  }
  private bool IsTargetPawnOkay() {
  return !this.TargetPawn.Dead && !this.TargetPawn.Downed;
  }
+
+ //NEW: Pawns now check to see if the other pawn rejected them recently (in last 3 minutes) before bothering
+ // to try again.  Should significantly curtail hookup spam, although there may be edge cases (jobs on both
+ // sides of the map, pawns keep running back and forth across the map to attempt a hookup).
+ private bool WasRebuffedByTargetPawn() {
+ if(actor.needs.mood.thoughts.memories.Memories.Any(x => SexualityUtilities.IsRebuffedHookupThought(x, this.TargetPawn, 10800))) return true;
+ return false;
+ }
  private bool IsTargetPawnFreeForHookup() {
- return !PawnUtility.WillSoonHaveBasicNeed(this.TargetPawn) && !PawnUtility.EnemiesAreNearby(this.TargetPawn, 9, false) && this.TargetPawn.jobs.curJob.def != JobDefOf.LayDown && this.TargetPawn.jobs.curJob.def != JobDefOf.BeatFire && this.TargetPawn.jobs.curJob.def != JobDefOf.Arrest && this.TargetPawn.jobs.curJob.def != JobDefOf.Capture && this.TargetPawn.jobs.curJob.def != JobDefOf.EscortPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.ExtinguishSelf && this.TargetPawn.jobs.curJob.def != JobDefOf.FleeAndCower && this.TargetPawn.jobs.curJob.def != JobDefOf.MarryAdjacentPawn && this.TargetPawn.jobs.curJob.def != JobDefOf.PrisonerExecution && this.TargetPawn.jobs.curJob.def != JobDefOf.ReleasePrisoner && this.TargetPawn.jobs.curJob.def != JobDefOf.Rescue && this.TargetPawn.jobs.curJob.def != JobDefOf.SocialFight && this.TargetPawn.jobs.curJob.def != JobDefOf.SpectateCeremony && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeToBedToOperate && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeWoundedPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.UseCommsConsole && this.TargetPawn.jobs.curJob.def != JobDefOf.Vomit && this.TargetPawn.jobs.curJob.def != JobDefOf.Wait_Downed;
+ return !WasRebuffedByTargetPawn() && !PawnUtility.WillSoonHaveBasicNeed(this.TargetPawn) && !PawnUtility.EnemiesAreNearby(this.TargetPawn, 9, false) && this.TargetPawn.jobs.curJob.def != JobDefOf.LayDown && this.TargetPawn.jobs.curJob.def != JobDefOf.BeatFire && this.TargetPawn.jobs.curJob.def != JobDefOf.Arrest && this.TargetPawn.jobs.curJob.def != JobDefOf.Capture && this.TargetPawn.jobs.curJob.def != JobDefOf.EscortPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.ExtinguishSelf && this.TargetPawn.jobs.curJob.def != JobDefOf.FleeAndCower && this.TargetPawn.jobs.curJob.def != JobDefOf.MarryAdjacentPawn && this.TargetPawn.jobs.curJob.def != JobDefOf.PrisonerExecution && this.TargetPawn.jobs.curJob.def != JobDefOf.ReleasePrisoner && this.TargetPawn.jobs.curJob.def != JobDefOf.Rescue && this.TargetPawn.jobs.curJob.def != JobDefOf.SocialFight && this.TargetPawn.jobs.curJob.def != JobDefOf.SpectateCeremony && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeToBedToOperate && this.TargetPawn.jobs.curJob.def != JobDefOf.TakeWoundedPrisonerToBed && this.TargetPawn.jobs.curJob.def != JobDefOf.UseCommsConsole && this.TargetPawn.jobs.curJob.def != JobDefOf.Vomit && this.TargetPawn.jobs.curJob.def != JobDefOf.Wait_Downed;
  }
  [DebuggerHidden]
  protected override IEnumerable<Toil> MakeNewToils() {
@@ -1543,6 +1562,27 @@
  }
 
  public static class SexualityUtilities {
+ public static JobDef hookupJob = DefDatabase<JobDef>.GetNamed("TryHookup", false);
+
+ //NEW: Provides a spam-blocker on hookup attempts, preventing pawns from trying another hookup if they
+ // tried recently, and also allowing other pawns to try a reverse hookup attempt for auto-acceptance.
+ /// <summary>
+ /// Returns true if the checked thought is in fact a hookup-rebuff thought, and it falls within the specified age in ticks.  Intended to be used from lambda expressions that run on a pawn's memories.
+ /// </summary>
+ /// <param name="thought">The thought that we suspect is a <seealso cref="RRRThoughtDefOf.RebuffedMyHookupAttempt"/>.
+ /// Normally passed from a lambda expression/predicate (e.g., <seealso cref="JobDriver_LeadHookup.WasRebuffedByTargetPawn()"/>)</param>
+ /// <param name="rebuffer">The pawn who would have rebuffed the person who owns the thought.</param>
+ /// <param name="maxAgeInTicks">The oldest that the thought can be before it will be excluded from consideration.</param>
+ /// <returns>True if there is still an active "rebuff" in my recent memory, false otherwise.</returns>
+ public static bool IsRebuffedHookupThought(Thought_Memory thought, Pawn rebuffer, int maxAgeInTicks = int.MaxValue) {
+ if(thought.def.defName == RRRThoughtDefOf.RebuffedMyHookupAttempt.defName) {
+ Thought_MemorySocial rebuff = (Thought_MemorySocial)thought;
+ //Log.Message("DEBUG: rebuff.age =" + rebuff.age.ToString());
+ return (rebuff.otherPawn == rebuffer) && (rebuff.age <= maxAgeInTicks);
+ }
+ return false;
+ }
+
  public static Pawn FindAttractivePawn(Pawn p1) {
  Pawn result;
  if (p1.story.traits.HasTrait(RRRTraitDefOf.Asexual)) {
@@ -1577,6 +1617,10 @@
  else if ((double)p1.relations.SecondaryRomanceChanceFactor(pawn) < 0.05) {
  result = null;
  }
+ //NEW: If they've recently rebuffed me, I won't bother asking and will just find someone else (or nobody at all)
+ else if (p1.needs.mood.thoughts.memories.Memories.Any(x => SexualityUtilities.IsRebuffedHookupThought(x, pawn, 10800))) {
+ result = null;
+ }
  else {
  result = pawn;
  }
@@ -1628,17 +1672,32 @@
  return result;
  }
  public static bool IsHookupAppealing(Pawn pSubject, Pawn pObject) {
- bool result;
  if (PawnUtility.WillSoonHaveBasicNeed(pSubject)) {
- result = false;
+ return false;
  }
  else {
  float num = 0f;
  num += pSubject.relations.SecondaryRomanceChanceFactor(pObject) / 1.5f;
  num *= Mathf.InverseLerp(-100f, 0f, (float)pSubject.relations.OpinionOf(pObject));
- result = (Rand.Range(0.05f, 1f) < num);
+
+ //NEW: pawns who are needy will be more willing to accommodate a hookup request
+ if(0.10f < num) { //is there a snowball's chance in a mechanoid's inferno cannon I'd ever casually boink this person?
+ Need_Joy joy = (Need_Joy)pSubject.needs.TryGetNeed(NeedDefOf.Joy);
+ if(pSubject.CurJobDef == hookupJob) { //I'm already trying to find a Tinder date, but you're closer... sure
+ return true;
+ }
+ if(joy != null) {
+ if(joy.CurCategory == JoyCategory.Empty) { //I'm so incredibly bored that I'll do anything with two legs just to get a moment's thrill... sure
+ return true;
+ }
+ else if(joy.CurCategory <= JoyCategory.Low) { //I'm not incredibly bored, but I'm *pretty* bored...
+ //Although it would be possible to divide by zero with this formula, the possible range is by definition [0.01f, 0.3f) because of the auto-success at Empty joy
+ num /= Mathf.Lerp(0.0f, 0.3f, joy.CurLevel); //e.g., divides value by 1.0 (no change) at joy 0.3, divides value by 0.333 (+200%) at joy 0.10
+ }
+ }
+ }
+ return (Rand.Range(0.05f, 1f) < num);
  }
- return result;
  }
  public static bool WillPawnTryHookup(Pawn p1) {
  bool result;

13
Releases / Re: [1.0] Simple Slavery
« on: June 26, 2019, 02:52:37 AM »
Slave collars in leather, metal, high-security, shock, and explosive varieties; purchase slaves rather than automatically freeing them; take slaves from prisoners instead of only befriending and recruiting voluntary colonists; a chance that slaves escape which diminishes as their indoctrination increases; choosing whether to shackle, for harder escapes, or not, for greater productivity; some negative and positive thoughts for living on the avails of slavery; and uprisings if the helot population starts to overwhelm the citizen population.  That's basically it, yep.  It is called Simple Slavery.

Simple Slavery is more of a "fix" than a "feature".  The idea is more to give you the freedom to do something that was arbitrarily or negligently restricted.  In vanilla, you are forced to play the good guy by emancipating anyone you "purchase", or forced to grant prisoners sovereignty to be recruited only by their own free will.  Simple Slavery changes that to let you be the bad guy, if you want.  It's especially relevant for self-imposed challenges, like trying to make a tribal civilisation that is founded on slavery, rather than as a core feature that every colony would want or need.

For the giant morality play that is RimWorld, oversights and design decisions like those on Ludeon's part tend to bother me.  I can see why they defaulted to no-condoning-of-slavery, of course, given the social-justice crusade against Tynan's various design decisions that weren't actually important parts of the game in the first place.  It's mods like this that fix those oversights, and the best part is that they fix it without going overboard.  More advanced mods could certainly delve into the squickier territories like forced castration, punishments and whippings, threats and applications of force, deliberate crippling to prevent escape, etc., which would all be quite realistic.  However, anyone who did such a mod would probably be trying more to live out their fantasies or racisms rather than trying to satisfy the conceptual need that there are slaves on the world that you couldn't be involved with before.

14
Mods / Re: SCP FOUNDATION MOD & SCENARIO REQUEST
« on: December 13, 2018, 06:27:01 AM »
I had to take a second to look up "SCP" on Google for those of us who don't brigade suggestions without actually saying what they mean. ;-)

But wouldn't that be The Agency?

15
there's only a couple of options because the grid is a ushort with tiny numbers, i can change how it all works if i  get a chance, and allow for more granularity in the settings

Aha.  Perhaps the cleanup rate could just be modified further by a random throw for any cleanup iteration?  That would allow granularity without having to refactor variable types or waste memory unnecessary on a massive matrix of floats, although it would offload a bit of work onto the CPU.

Pages: [1] 2 3 ... 9