Looking for help understanding how to code a conditional event

Started by big-daddio, April 19, 2019, 03:56:28 PM

Previous topic - Next topic

big-daddio

Trying to create an event that is triggered at or shortly after the first raid.  I believe it would need to be a class inherited from incidentWorker, and I can see a global variable that counts the number of raids, it's just I'm not sure how any new class would fit into the tick system so that it is evaluated every so often.

Any advice or even a general direction to go down would be appreciated.

LWM

If no one comes up with more concrete suggestions, looking into the Man In Black event might help?

--LWM

big-daddio

If I could find the hook for that event I would.  Looking at the defs for the man in black incident, it goes to class incidentWorker_WandererJoined and IlSpy doesn't show where that class is instantiated.

LWM

RimWorld/IncidentWorker_WandererJoin.cs

I preferred dnSpy, for what it's worth - I wrote out the entire codebase as a project, so I can use file search to look for tags if I need.

But that's not going to help you in this case...  However, the incident has a defName of StrangerInBlackJoin....which also shows up in the xml for the storytellers!  In the <comps> section, there's this:


      <!-- Triggered -->
      <li Class="StorytellerCompProperties_Triggered">
        <incident>StrangerInBlackJoin</incident>
        <delayTicks>180</delayTicks>
      </li>


So that comp class looks like a good place to look!  And expect you may have to do an xpath patch for storytellers if you want it to show up?

--LWM

Mehni

Quote from: big-daddio on April 20, 2019, 04:37:45 PM
it goes to class incidentWorker_WandererJoined and IlSpy doesn't show where that class is instantiated.

No surprise there; RimWorld almost never directly instantiates classes, certainly not classes referenced in XML. If the XML does contain a class, point your decompiler to that Def's field. For instance, type in def.Worker in your favourite decompiler and see what all pops up. This rather abstract design pattern is repeated for multiple things, in different ways.

As for "the first raid", that's a bit tricky. Cassandra and Phoebe both use "StorytellerCompProperties_ClassicIntro" so they have fixed behaviour for the first few days. Randy however does what he wants. I would suggest you introduce your own "StorytellerComp" into (all) existing storytellers which does what you want.

big-daddio

SOLVED

I figured it out and other than one gaffe, got it right on my first try.  I forgot to include the namespace for my replacement (bolded in the xlm below) incidentWorker_RaidEnemy class.

Just some context, I'm just starting out trying to mod and sharpen my skills (my CS degree is probably older than many of you) so created a mod Hen Thirteen (in steam workshop).  Hen 13 is a viscous killer (ala Monty Python rabbit), so why have the mod if you're not going to get a Hen13 except by Prepare Carefully or random chance one joins ala terriers.  So, I wanted one to automatically spawn to the rescue on the first raid.

So this is what I did.
In top level MyMod/Patches I have this xml

<?xml version="1.0" encoding="utf-8" ?>
<Patch>
  <Operation Class="PatchOperationReplace">
    <xpath>/Defs/IncidentDef[defName="RaidEnemy"]/workerClass</xpath>
    <value>
      <workerClass>HenThirteen.IncidentWorker_RaidEnemy_HenThirteen</workerClass>
    </value>
  </Operation>
</Patch>

In my HenThirteen namespace I added this new class

// We take from the base IncidentWorker_RaidEnemy class and override the TryExecuteWorker method
// Then we can call the core/base TryExecuteWorker method and do something if it's the
// first instance of an enemy raid using the global int numRaidsEnemy

public class IncidentWorker_RaidEnemy_HenThirteen : IncidentWorker_RaidEnemy
    {
        protected override bool TryExecuteWorker(IncidentParms parms)
        {
            Log.Message("We made it to new incidentworker_raidenemy_henthirteen. yay!.  Number of raids is" + Find.StoryWatcher.statsRecord.numRaidsEnemy.ToString(), true);
            // do all the things the base class does
            base.TryExecuteWorker(parms); 
           
            // if it's the first raid do more things.  in our case we'll add code to spawn a trained hen13
            if (Find.StoryWatcher.statsRecord.numRaidsEnemy == 1)
            {
                Log.Message("This should be the first raid.  Number of raids is " +  Find.StoryWatcher.statsRecord.numRaidsEnemy.ToString());
                // spawn a new hen 13 here and make it part of colony
            }
            return true;
        }
    }