-
Notifications
You must be signed in to change notification settings - Fork 3
How To Use
We'll walk through an example here, and explain how to add each of the available features to a mod. To add terrain movement rules you only need XML -- no C# required. Let's start with a new animal, a Sand Worm.

This one is named Stuart Little.
The idea is that on desert maps this animal should move faster through sand than other terrain, while other pawns should move slower through sand.
To start let's copy MoveSpeed's definition and replace the defName, label, description defaultBaseValue, and minValue fields. We'll place this file in Defs/Stats/Stats_Sand.xml.
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<StatDef>
<defName>SandDrillingSpeed</defName>
<label>sand speed</label>
<description>Speed of movement in cells per second through sand.</description>
<category>BasicsPawn</category>
<defaultBaseValue>0</defaultBaseValue>
<minValue>0</minValue>
<hideAtValue>0</hideAtValue>
<toStringStyle>FloatTwo</toStringStyle>
<formatString>{0} c/s</formatString>
<displayPriorityInCategory>90</displayPriorityInCategory>
<capacityFactors>
<li>
<capacity>Moving</capacity>
<weight>1</weight>
</li>
</capacityFactors>
<parts>
<li Class="StatPart_Glow">
<humanlikeOnly>true</humanlikeOnly>
<factorFromGlowCurve>
<points>
<li>(0,0.80)</li>
<li>(0.30,1.00)</li>
</points>
</factorFromGlowCurve>
</li>
</parts>
<scenarioRandomizable>true</scenarioRandomizable>
</StatDef>
</Defs>This adds a SandDrillingSpeed stat which we'll both add to Stuart Little, and map to our TerrainDef later on.
With a new stat we'll want to add this stat to our pawn in Defs/ThingDefs_Races/SandWorm.xml.
<ThingDef ParentName="AnimalThingBase">
<defName>SandWorm</defName>
<label>worm</label>
<description>A large predatory worm that only lurks in sands.</description>
<statBases>
<MoveSpeed>1.0</MoveSpeed>
<SandDrillingSpeed>8.0</SandDrillingSpeed>
</statBases>
...We made the Stuart Little now have a MoveSpeed of 1 but a SandDrillingSpeed of 8, meaning we intend for this guy to be quite fast in sand.

Before we use this stat in the mod entirely let's add one more thing, a new pathCost stat. The game traditionally provides a field called pathCost on all terrain. This was used to calculate how slow it is to move through certain terrain types. However some terrain can support multiple movement types, like water tiles where you might want to be able to walk or swim depending on which is faster.
Thus we're going to add a pathCostSandDrilling to Defs/Stats/Stats_Sand.xml.
<StatDef>
<defName>pathCostSandDrilling</defName>
<label>path cost for drilling through sand</label>
<description>The pathing addition for passing through via sand drilling.</description>
<category>BasicsNonPawn</category>
<defaultBaseValue>0</defaultBaseValue>
<hideAtValue>0</hideAtValue>
<toStringStyle>FloatOne</toStringStyle>
<applyFactorsIfNegative>false</applyFactorsIfNegative>
</StatDef>We have some new StatDefs but they're tied to any terrain tile yet. Let's patch the Sand TerrainDef now to add our new pathCost and move stats in Patches/PatchSand.xml.
<?xml version="1.0" encoding="utf-8" ?>
<Patch>
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationTest">
<xpath>*/TerrainDef[defName = "Sand"]/statBases</xpath>
<success>Invert</success>
</li>
<li Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]</xpath>
<value>
<statBases/>
</value>
</li>
</operations>
</Operation>
<Operation Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]/statBases</xpath>
<value>
<pathCostSandDrilling>2</pathCostSandDrilling>
</value>
</Operation>
</Patch>This patch does a safe addition of a new statBases to include pathCostSandDrilling with a value of 2, which means moving through sand with a SandDrillingSpeed stat will be the same ratio of expense as MoveSpeed over Soil. Technically you can skip this step if you want to use MoveSpeed for everything, but we add it here because you may want to differentiate terrain movements by statistic.
For the final piece, we need to add a mod extension to tell the TMK library how to include our new stats in pathing calculations. To do this we're going to add a DefModExtension.
<modExtensions>
<li Class="TerrainMovement.TerrainMovementStatDef">
<pawnSpeedStat>SandDrillingSpeed</pawnSpeedStat>
<terrainPathCostStat>pathCostSandDrilling</terrainPathCostStat>
</li>
</modExtensions>Now since Sand is an already existing Def we'll actually need to patch it by adding this to Patches/PatchSand.xml.
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationTest">
<xpath>*/TerrainDef[defName = "Sand"]/modExtensions</xpath>
<success>Invert</success>
</li>
<li Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]</xpath>
<value>
<modExtensions/>
</value>
</li>
</operations>
</Operation>
<Operation Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]/modExtensions</xpath>
<value>
<li Class="TerrainMovement.TerrainMovementStatDef">
<pawnSpeedStat>SandDrillingSpeed</pawnSpeedStat>
<terrainPathCostStat>pathCostSandDrilling</terrainPathCostStat>
</li>
</value>
</Operation>And now we've registered our SandDrillingSpeed and pathCostSandDrilling stats with Sand terrain! Pawns will now prioritize using these stat combinations for moving through sand when they faster to use than MoveSpeed and pathCost respectfully.
Say we're now happy with our speed sand worm, but we want it to be a little more thematic and be required to stay on Sand and not travel elsewhere. That's possible as well.
To enable this feature our Sand TerrainDef needs to have an appropriate tag. Let's add Sandy to Patches/PatchSand.xml.
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationTest">
<xpath>*/TerrainDef[defName = "Sand"]/tags</xpath>
<success>Invert</success>
</li>
<li Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]</xpath>
<value>
<tags/>
</value>
</li>
</operations>
</Operation>
<Operation Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName = "Sand"]/tags</xpath>
<value>
<li>Sandy</li>
</value>
</Operation>This groups terrain together by tag so we can lookup when pathing if movement is allowed.
To make pawns avoid the terrain tag we just added we need another ModExtensionDef in our Defs/ThingDefs_Races/SandWorm.xml file.
...
</statBases>
<modExtensions>
<li Class="TerrainMovement.TerrainMovementPawnRestrictions">
<stayOnTerrainTag>Sandy</stayOnTerrainTag>
</li>
</modExtensions>
...This tells the TMK kit to restrict Stuart Little to Sandy tagged terrain only. Now Stuart Little is stuck to this area:

Alternatively if we wanted the worm to just avoid certain terrain types we could have added the following.
...
</statBases>
<modExtensions>
<li Class="TerrainMovement.TerrainMovementPawnRestrictions">
<stayOffTerrainTag>Water</stayOffTerrainTag>
</li>
</modExtensions>
...This would constrain the Worms to avoid water rather than stay only on sand.
Some advanced use-cases are captured in the extended use page. These aren't needed to get utility out of the mod, but allow for more nuanced behavior and application of rules.