SHORTTUTORIAL: How Pawns Think - roxxploxx/RimWorldModGuide GitHub Wiki
The AI of RimWorld is a web of classes and hierarchies of nodes. ThinkTrees are a hierarchy of nodes that calculate priorities based upon game conditions, to select the best current job. Each
Pawn
determines what to do in it'sPawn_JobTracker
(i.e.Pawn.tracker
), identifying aJob
and using aJobDriver
to specify every detail of that job in a list ofToil
s.
You can find ThinkTreeDefs XML files in the ThinkTreeDefs folder for Animal, Humanlike and Mechanoid. There are also files for subtrees used across these. ThinkTreeDefs have a string defName
, ThinkNode thinkRoot
, string insertTag
and int insertPriority
. The defName is useful for cross referencing these nodes. So, you could add in a <ThinkTreeDef>
entry outside this hierarchy by referencing that defName via the tag. The thinkRoot
stores other sub nodes (i.e. List<ThinkNodes> subNodes
) and it's purpose is to select among these sub nodes for a valid ThinkResult
. This ThinkResult
stores the Job
and the ThinkNode
that asked for it.
Of importance for modders are the <insertTag>
. If you create a ThinkTreeDef of your own, you can specify an <insertTag>
like this, <insertTag>Humanlike_PostMain</insertTag>
, to insert your new ThinkTreeDef into the existing ThinkTree.
A Job
holds the JobDef
and Pawn that does it, to make the Pawn do something in the game, that the Pawn or the player thought was a good idea (i.e. the ThinkTrees computed it). The Job
though is really only a container to track how something gets done. The JobDriver
class, whose Type is specified by the <driverTag>
in <JobDef>
, is where the actual definition of how to do the job is done. It is broken down into individual Toils that are completed one at a time, in order. There are many types of Toils so you'll have to look through them later.
Ok, so you're a Wizard Larry. And Larry wants to study up on his spells. So, let's create a job to do just that at a Wizard Alcove.
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<JobDef>
<defName>UM_StudyWizardryJob</defName>
<driverClass>UnificaMagica.JobDriver_StudyWizardry</driverClass>
<reportString>studying wizardry.</reportString>
</JobDef>
</Defs>
This section of XML create a new JobDef and says there is a class in the namespace "UnificaMagica" (my Mod) that will list the Toils to get it done.
adapted from Jecrell's "Star Wars - The Force" mod.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Verse;
using Verse.AI;
using RimWorld;
namespace UnificaMagica
{
public class JobDriver_StudyWizardry : JobDriver
{
private Rot4 faceDir;
// This class generates a list of Toils (a new one each time as per the 'yield' command)
// that are managed by the JobDriver in the Pawn_JobTracker.
[DebuggerHidden]
protected override IEnumerable<Toil> MakeNewToils()
{
yield return Toils_Reserve.Reserve(TargetIndex.A, 1);
yield return Toils_Goto.GotoCell(TargetIndex.A, PathEndMode.OnCell);
yield return new Toil
{
initAction = delegate
{
this.faceDir = ((!this.CurJob.def.faceDir.IsValid) ? Rot4.Random : this.CurJob.def.faceDir);
},
tickAction = delegate
{
this.pawn.Drawer.rotator.FaceCell(this.pawn.Position + this.faceDir.FacingCell);
this.pawn.GainComfortFromCellIfPossible();
if (this.pawn.TryGetComp<CompAbilityUserWizard>() != null)
{
CompAbilityUserWizard wizardComp = this.pawn.GetComp<CompAbilityUserWizard>();
... do stuff ...
if (! stop condition )
{
... do stuff ...
else {
this.EndJobWith(JobCondition.Succeeded);
}
}
},
defaultCompleteMode = ToilCompleteMode.Delay,
defaultDuration = 1800
};
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look<Rot4>(ref this.faceDir, "faceDir", default(Rot4), false);
}
}
}