I want to make a building that can only be placed on water, but no matter where I try to place it it says "the terrain can't support this". The only way I can get this to not happen is to remove <terrainAffordanceNeeded>, but then it can be placed everywhere BUT water (i.e. anywhere a wall could be placed). How can I have a building that only can be placed on water?
What doees your current definition look like?
PlaceWorkers C# code just returns true no matter what right now FYI. Here's my definition:
<ThingDef Name="LightDam">
<thingClass>Building</thingClass>
<category>Building</category>
<defName>LightDam</defName>
<label>light dam</label>
<description>A sturdily-constructed (hopefully!) pile of wood across a river for your colonists to stand on. Beware of beavers with patents!</description>
<soundImpactDefault>BulletImpactWood</soundImpactDefault>
<selectable>true</selectable>
<repairEffect>Repair</repairEffect>
<graphicData>
<texPath>LightDam</texPath>
<graphicClass>Graphic_Single</graphicClass>
<damageData>
<rect>(0,0,1,1)</rect>
<enabled>false</enabled>
</damageData>
</graphicData>
<blueprintGraphicData>
<texPath>LightDamBlueprint</texPath>
</blueprintGraphicData>
<uiIconPath>LightDam</uiIconPath>
<drawerType>MapMeshAndRealTime</drawerType>
<statBases>
<MaxHitPoints>50</MaxHitPoints>
<WorkToBuild>1500</WorkToBuild>
<Flammability>1.0</Flammability>
</statBases>
<costStuffCount>30</costStuffCount>
<leaveResourcesWhenKilled>false</leaveResourcesWhenKilled>
<altitudeLayer>Floor</altitudeLayer>
<passability>Standable</passability>
<blockWind>false</blockWind>
<castEdgeShadows>true</castEdgeShadows>
<fillPercent>1</fillPercent>
<coversFloor>true</coversFloor>
<placingDraggableDimensions>2</placingDraggableDimensions>
<tickerType>Never</tickerType>
<rotatable>false</rotatable>
<neverMultiSelect>false</neverMultiSelect>
<holdsRoof>false</holdsRoof>
<designationCategory>Structure</designationCategory>
<staticSunShadowHeight>1.0</staticSunShadowHeight>
<blockLight>false</blockLight>
<canOverlapZones>false</canOverlapZones>
<stuffCategories>
<li>Woody</li>
</stuffCategories>
<building>
<isInert>true</isInert>
<ignoreNeedsPower>true</ignoreNeedsPower>
</building>
<damageMultipliers>
<li>
<damageDef>Bomb</damageDef>
<multiplier>50</multiplier>
</li>
</damageMultipliers>
<!--<terrainAffordanceNeeded>Undefined</terrainAffordanceNeeded>-->
</ThingDef>
Did you try to add <affordances> values to water terrain definitions as it is done for any kind of TerrainDefs. I am not into details yet, but it seems to me you need to make the water some kind of "floor" if you know what i mean.
I could imagine for water:
<affordances>
<li>liquid</li>
</affordances>
But I have no idea where the info is picked up in the code. Just some idea I would start to follow.
Your building should then reflect this value in <terrainAffordanceNeeded>.
Quote from: battlemage64 on November 02, 2017, 08:06:28 PMHow can I have a building that only can be placed on water?
You're going to need both XML and C#. First, via XML patching, you'll need to add the "Undefined" affordance to water tiles. (By default, they have no affordances at all, which is *not* the same thing a having the "Undefined" affordance.) Then, via C#, you'll need to create a custom Placeworker method which rejects any terrain type that isn't water. (This will disallow construction of your building on terrain tiles to which other mods have added the "Undefined" affordance.)
Varisha: Thanks a lot, I'll try that.
dburgdorf: Thanks, I'll also try this. I already have my PlaceWorkers coded to do that, and it works (because I ripped off your code for Basic Bridges ;)). [EDIT: Thought removed because I figured it out] I hope this works!
EDIT: Okay, so here's my PatchOperation and PlaceWorkers. Please tell me if it looks wrong, especially the last line of PlaceWorkers. It currently is NOT working, I can't place a dam onshore or offshore (I think it's a problem with the patch operation?).
<Operation Class="PatchOperationAdd">
<xpath>*/TerrainDef[defName="WaterShallow"]</xpath>
<value>
<affordances>
<li>Undefined</li>
</affordances>
</value>
</Operation>
(and again for WaterShallowMoving)
-------------------------------------------------
public override AcceptanceReport AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Thing thingToIgnore = null)
{
TerrainDef terrainDef = base.Map.terrainGrid.TerrainAt(loc);
if (terrainDef == TerrainDef.Named("WaterMovingShallow") || terrainDef == TerrainDef.Named("WaterShallow"))
{
return true;
} else {
return new AcceptanceReport("Dams.LightDam".Translate()); //I'm not sure if this should return false, but this is what I see in other mods. What's the right way?
}
}
:)
I don't see anything obviously wrong with either your patch or your placeworker code. (And I assume you're not getting any error messages about the patch, since you haven't mentioned any.) But I do notice that the XML def for the dam doesn't seem to include a *call* to the placeworker....
(As far as the placeworker "false" return is concerned, what you're doing there is telling the game to pop up the defined text on screen so the player knows why the placement failed. The structure's correct.)
EDIT:
Everything has fallen apart.
For some reason, when I reverted from A18 to A17, every time I open RW I get an error that says "XML error: <volumeAmbient>1</volumeAmbient> doesn't correspond to any field in type PrefsData." I have no idea what this is, it shows up with or without mods. Additionally, it says that it can't get any usable data from my patch operations, which is the EXACT SAME as I commented before but with a pair of <Patch> and </Patch> tags around it. I can't place the dam anywhere and I have no idea what's going on.
Today I learned I can learn how to code a robot in 10 minutes, but I can't fix a single stupid error. Somebody please help.
It works! I just had to move my patch operations to Mod/Patches (I had them in Mod/Defs because I thought they were defs) and now it works fine!