Gatherer Spot - KonradHeinser/EBSGFramework GitHub Wiki
The Gatherer Spot comp (not to be confused with vanilla's Gather Spot comp), allows a spot to be designated which colonists can use as a central point for looking around the area to magically find the things you specify. These spots also have special placeworkers available to restrict where they can be placed, if so desired. Almost all of the settings for this comp, including for the job, reside within this comp on the building's ThingDef:
<comps>
<li Class="EBSGFramework.CompProperties_GathererSpot">
<options>
<li>
<amountOnFind>#~#</amountOnFind>
<thing>InsertDefNameHere</thing>
</li>
<li>
<amountOnFind>#~#</amountOnFind>
<thing>InsertDefNameHere</thing>
</li>
<li>
<amountOnFind>#~#</amountOnFind>
<thing>InsertDefNameHere</thing>
</li>
</options>
</li>
</comps>
While the options section is all you technically need to fill in, there's also additional options that can be filled in that the job will use
- options : Contains the options for what is created when the pawn is finally done working. This can be limited to one option, or extended to include a myriad of options. Each thing to create requires its own li, which has the following tags available
- amountOnFind : A range of numbers to pick from when generating the items. If numbers below 1 are included, then any time those are picked, nothing is found (i.e. putting 0~1 will cause a 50% chance to find 1 item.)
- thing : The ThingDef to create
- stuff : The stuff to make the ThingDef out of. If the ThingDef is not stuffable, don't include this as it will cause errors
- weight : Default (1) : Alters the chance that this option will be picked. If there's only one option, this doesn't have an impact
- gatherRadius : Default (10) : How far from the building the pawn actually walks. This is purely aesthetic, and usually isn't worth changing unless you have conditions set up later that have an area size notably different from this one
- focusWanderInWater : Default (False) : When true, the pawn will focus on walking through any water in the gatherRadius, assuming there is some. While false, the pawn will try to stay out of water, but may still end up walking through some if there is a lot nearby
- ticksNeededToFindSomething : Default (1500~2500) : The range of time it will take to find something. The minimum should always be above 600 ticks, with over 1000 ticks being ideal. If the pawn needs to stop for any reason, all progress is lost, so keep that in mind when setting up tick count and option finds. Instead of creating extremely long job durations, it may be better to set up fail chances. This doesn't include time to return to the gatherer's spot to place the item
- gatheringSound : Sustainer played while gathering is in progress
- gatheringFinishedSound : Sound played when progress is complete, regardless of whether it is successful or not
Next is setting up the WorkGiver. The only hard requirements for this are the giverClass (EBSGFramework.WorkGiver_Gatherer) and a relatedThing specified in the EBSGExtension, so in theory the rest should be completely customizable:
<WorkGiverDef>
<defName>EBSG_GoldPanning</defName>
<label>pan at gold panning spot</label>
<giverClass>EBSGFramework.WorkGiver_Gatherer</giverClass>
<workType>Crafting</workType>
<priorityInType>200</priorityInType>
<verb>pan</verb>
<gerund>panning at</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<prioritizeSustains>true</prioritizeSustains>
<modExtensions>
<li Class="EBSGFramework.EBSGExtension">
<relatedThing>EBSG_GoldPanningSpot</relatedThing>
</li>
</modExtensions>
</WorkGiverDef>
You can also change the job report string by setting a relatedJob in the extension attached to the WorkGiverDef. The only requirement for the JobDef is that it uses the EBSGFramework.JobDriver_Gatherer driverClass. This will default to EBSG_GathererJob
<JobDef>
<defName>EBSG_GathererJob</defName>
<driverClass>EBSGFramework.JobDriver_Gatherer</driverClass>
<reportString>Finding things near TargetA.</reportString>
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
</JobDef>
When you're setting up options, you can set terrain conditions that cause them to only be available when those conditions are met. These conditions are in relation to the building itself, not the cells that the pawns will be wandering. While less than ideal, it's set up this way to make it significantly less performance heavy to check the conditions.
In cases where the terrain around the building changes, it may take a while for the building to register these changes and update the viable options list. Saving and reloading should cause the list to be remade either way, so if the building keeps refusing to update the list, I recommend trying that.
These tags can be added to any of the li's in the options:
- nearbyWaterTilesNeeded : Default (0) : Creates requirement that there be water nearby for this option to be valid. If set to -1, it requires that there be no water within the specified range
- maxWaterDistance : Default (1.9) : How far to look for water
- nearbyTerrainsNeeded : An li of li's that requires one of each sub-li be met for the option to be valid. For an example of this headache generator, I've added a mini example below. For another thing that uses the same concept, look at the requireOne tag that many MemeDefs use
- li : This is the only tag available directly within nearbyTerrainsNeeded. Each li at this level is a separate set of conditions that must be met
- li : Condition to check
- terrain : The TerrainDef to check for
- count : Default (1) : How many need to be in the area. If set to 0 or lower, then this will check that none of the terrain is in the area
- maxDistance : Default (10) : The size of the area to check
- li : Condition to check
- li : This is the only tag available directly within nearbyTerrainsNeeded. Each li at this level is a separate set of conditions that must be met
This is an example of a nearbyTerrainsNeeded
<nearbyTerrainsNeeded>
<li>
<li> <!--Can't be near an ocean-->
<terrain>WaterOceanShallow</terrain>
<count>0</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li> <!--Needs to be on or next to certain types of terrain-->
<li>
<terrain>Soil</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>SoilRich</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
There is also a special placeWorker that can be attached to the ThingDef that will check when placing. This placeWorker checks conditions specified in the comp. They are intentionally set to be the exact same as the conditions you can set in the options to make it easier to switch from one place to another (i.e. To test the condition with the placeworker before throwing it in the specific option.) If there are conditions that all of your options must meet, this may help simplify the process for players by restricting where they can place them in addition to restricting the options.
<placeWorkers>
<li>EBSGFramework.PlaceWorker_GathererTerrain</li>
</placeWorkers>
This is just a repeat of the stuff in Giving Options Conditions. Scrolling up also works:
- nearbyWaterTilesNeeded : Default (0) : Creates requirement that there be water nearby for this option to be valid. If set to -1, it requires that there be no water within the specified range
- maxWaterDistance : Default (1.9) : How far to look for water
- nearbyTerrainsNeeded : An li of li's that requires one of each sub-li be met for the option to be valid. For an example of this headache generator, I've added a mini example below. For another thing that uses the same concept, look at the requireOne tag that many MemeDefs use
- li : This is the only tag available directly within nearbyTerrainsNeeded. Each li at this level is a separate set of conditions that must be met
- li : Condition to check
- terrain : The TerrainDef to check for
- count : Default (1) : How many need to be in the area. If set to 0 or lower, then this will check that none of the terrain is in the area
- maxDistance : Default (10) : The size of the area to check
- li : Condition to check
- li : This is the only tag available directly within nearbyTerrainsNeeded. Each li at this level is a separate set of conditions that must be met
These two example contain most of the things available with this comp. If you plan on using them as a more direct reference for your own spots, please remember that these ones are only set up to check for vanilla terrains, so you may need to make additional compatibility patches.
The first example is a "gold panning spot", which must be placed next to any water's edge that is not an ocean, and must be placed on or next to soil, rich soil, or sand. After spending some time wandering around in the nearby water, the pawn has a 10% chance to find 1-10 gold.
The second example showcases a more complex gatherer's spot, where the spot is placed on a "beach" of some sort (by the ocean, on a river bank, or the "beach" of a pond/lake) and the available finds become based on what terrain is nearby. If close to both an ocean and a river, all of them become available, thus increasing the chance of finding some wood. This also contains an example of the other way to make a chance for "failure", as wood found by the non-oceanic water has a 50% chance of picking a number below 1, which results in nothing being made.
Both examples also include their work givers, both in this case using the "crafting" work type, and job defs that dictate what string is displayed on the pawn's info card. Remember that the JobDef is optional, as this framework will just default to its own JobDef if a specific one is not referenced in the work giver.
<ThingDef ParentName="BuildingBase">
<defName>EBSG_GoldPanningSpot</defName>
<label>gold panning spot</label>
<description>Designates a spot for panning gold. The spot in question needs to be a location adjacent to shallow moving water, and must be placed on or next to soil/sand that can be used to easily embed tools with minimal risk of losing them.</description>
<graphicData>
<texPath>Things/Building/Production/CraftingSpot</texPath>
<graphicClass>Graphic_Single</graphicClass>
</graphicData>
<altitudeLayer>FloorEmplacement</altitudeLayer>
<statBases>
<WorkToBuild>0</WorkToBuild>
</statBases>
<rotatable>false</rotatable>
<scatterableOnMapGen>false</scatterableOnMapGen>
<useHitPoints>False</useHitPoints>
<designationCategory>Production</designationCategory>
<passability>Standable</passability>
<placeWorkers>
<li>EBSGFramework.PlaceWorker_GathererTerrain</li>
</placeWorkers>
<comps>
<li Class="CompProperties_Forbiddable" />
<li Class="EBSGFramework.CompProperties_GathererSpot">
<nearbyWaterTilesNeeded>2</nearbyWaterTilesNeeded>
<focusWanderInWater>True</focusWanderInWater>
<nearbyTerrainsNeeded>
<li>
<li> <!--Can't be near an ocean-->
<terrain>WaterOceanShallow</terrain>
<count>0</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li> <!--Needs to be on or next to certain types of terrain-->
<li>
<terrain>Soil</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>SoilRich</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
<options> <!--Has a 10% chance to find 1-10 gold-->
<li>
<weight>9</weight>
<nearbyWaterTilesNeeded>2</nearbyWaterTilesNeeded>
<nearbyTerrainsNeeded>
<li>
<li> <!--Can't be near an ocean-->
<terrain>WaterOceanShallow</terrain>
<count>0</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li> <!--Needs to be on or next to certain types of terrain-->
<li>
<terrain>Soil</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>SoilRich</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
</li>
<li>
<thing>Gold</thing>
<amountOnFind>1~10</amountOnFind>
<nearbyWaterTilesNeeded>2</nearbyWaterTilesNeeded>
<nearbyTerrainsNeeded>
<li>
<li> <!--Can't be near an ocean-->
<terrain>WaterOceanShallow</terrain>
<count>0</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li> <!--Needs to be on or next to certain types of terrain-->
<li>
<terrain>Soil</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>SoilRich</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0.9</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
</li>
</options>
</li>
</comps>
<building>
<sowTag>SupportPlantsOnly</sowTag>
<canPlaceOverImpassablePlant>false</canPlaceOverImpassablePlant>
<ai_chillDestination>false</ai_chillDestination>
<artificialForMeditationPurposes>false</artificialForMeditationPurposes>
</building>
<designationHotKey>Misc11</designationHotKey>
</ThingDef>
<JobDef>
<defName>EBSG_GoldPanning</defName>
<driverClass>EBSGFramework.JobDriver_Gatherer</driverClass>
<reportString>Panning for goooolllddd</reportString>
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
</JobDef>
<WorkGiverDef>
<defName>EBSG_GoldPanning</defName>
<label>pan at gold panning spot</label>
<giverClass>EBSGFramework.WorkGiver_Gatherer</giverClass>
<workType>Crafting</workType>
<priorityInType>200</priorityInType>
<verb>pan</verb>
<gerund>panning at</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<prioritizeSustains>true</prioritizeSustains>
<modExtensions>
<li Class="EBSGFramework.EBSGExtension">
<relatedThing>EBSG_GoldPanningSpot</relatedThing>
<relatedJob>EBSG_GoldPanning</relatedJob>
</li>
</modExtensions>
</WorkGiverDef>
<ThingDef ParentName="BuildingBase">
<defName>BeachForagingSpot</defName>
<label>beach foraging spot</label>
<description>Designates a spot for foraging along the beachside, finding random materials as the pawn goes along.</description>
<graphicData>
<texPath>Things/Building/Production/CraftingSpot</texPath>
<graphicClass>Graphic_Single</graphicClass>
</graphicData>
<altitudeLayer>FloorEmplacement</altitudeLayer>
<statBases>
<WorkToBuild>0</WorkToBuild>
</statBases>
<rotatable>false</rotatable>
<scatterableOnMapGen>false</scatterableOnMapGen>
<useHitPoints>False</useHitPoints>
<designationCategory>Production</designationCategory>
<passability>Standable</passability>
<placeWorkers>
<li>EBSGFramework.PlaceWorker_GathererTerrain</li>
</placeWorkers>
<comps>
<li Class="CompProperties_Forbiddable" />
<li Class="EBSGFramework.CompProperties_GathererSpot">
<nearbyWaterTilesNeeded>3</nearbyWaterTilesNeeded> <!--Used in addition to the below water requirement to minimize the chance that it's not just one randomly generated bit of water-->
<maxWaterDistance>5</maxWaterDistance>
<gatherRadius>5</gatherRadius>
<nearbyTerrainsNeeded> <!--A list of options that are required.-->
<li>
<li> <!--Designates type of terrain it needs to be in. This is picking between one of the types of sand.-->
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
<li>
<terrain>SoftSand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
</li>
<li> <!--This requires specific types of nearby water to ensure something can be gathered-->
<li>
<terrain>WaterOceanShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
<li>
<terrain>WaterShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
<li>
<terrain>WaterMovingShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
<options>
<!--nearbyTerrainsNeeded on the options is still in relation to the building itself, these just allow for more specific situations involving specific types of water or the specific terrain the thing is sitting near.-->
<li>
<amountOnFind>1~2</amountOnFind> <!--Always finds at least 1-->
<thing>WoodLog</thing>
<nearbyWaterTilesNeeded>3</nearbyWaterTilesNeeded>
<maxWaterDistance>5</maxWaterDistance>
<nearbyTerrainsNeeded>
<li>
<li> <!--Only findable near an ocean-->
<terrain>WaterOceanShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
<li>
<terrain>SoftSand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
</li>
<li>
<amountOnFind>1</amountOnFind> <!--Unlike the driftwood, this always succeeds-->
<thing>Steel</thing>
<nearbyWaterTilesNeeded>3</nearbyWaterTilesNeeded>
<maxWaterDistance>5</maxWaterDistance>
<nearbyTerrainsNeeded>
<li>
<li> <!--Only findable near ponds and rivers-->
<terrain>WaterShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
<li>
<terrain>WaterMovingShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
<li>
<terrain>SoftSand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
</li>
<li>
<amountOnFind>-1~2</amountOnFind><!--How many to generate, with values zero and below being duds. In this case, there's only a 50% chance to find something when this is picked-->
<thing>WoodLog</thing>
<nearbyWaterTilesNeeded>3</nearbyWaterTilesNeeded>
<maxWaterDistance>5</maxWaterDistance>
<nearbyTerrainsNeeded>
<li>
<li> <!--Only findable near ponds and rivers-->
<terrain>WaterShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
<li>
<terrain>WaterMovingShallow</terrain>
<count>1</count>
<maxDistance>5</maxDistance>
</li>
</li>
<li>
<li>
<terrain>Sand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
<li>
<terrain>SoftSand</terrain>
<count>1</count>
<maxDistance>0</maxDistance>
</li>
</li>
</nearbyTerrainsNeeded>
</li>
</options>
</li>
</comps>
<building>
<sowTag>SupportPlantsOnly</sowTag>
<canPlaceOverImpassablePlant>false</canPlaceOverImpassablePlant>
<ai_chillDestination>false</ai_chillDestination>
<artificialForMeditationPurposes>false</artificialForMeditationPurposes>
</building>
<designationHotKey>Misc11</designationHotKey>
</ThingDef>
<JobDef>
<defName>ShoreForaging</defName>
<driverClass>EBSGFramework.JobDriver_Gatherer</driverClass>
<reportString>Foraging around TargetA.</reportString>
<allowOpportunisticPrefix>true</allowOpportunisticPrefix>
</JobDef>
<WorkGiverDef>
<defName>ShoreForaging</defName>
<label>forage at beach foraging spot</label>
<giverClass>EBSGFramework.WorkGiver_Gatherer</giverClass>
<workType>Crafting</workType>
<priorityInType>200</priorityInType>
<verb>gorage</verb>
<gerund>foraging at</gerund>
<requiredCapacities>
<li>Manipulation</li>
</requiredCapacities>
<prioritizeSustains>true</prioritizeSustains>
<modExtensions>
<li Class="EBSGFramework.EBSGExtension">
<relatedThing>BeachForagingSpot</relatedThing>
<relatedJob>ShoreForaging</relatedJob>
</li>
</modExtensions>
</WorkGiverDef>