Modding:Zone Builders

This page is about modding. See the modding overview for an abstract on modding.
For best results, it's recommended to have read the following topics before this one:

Zone builders

Zone builders are classes in the XRL.World.ZoneBuilders namespace that are successively applied during the generation of a zone. Each builder operates on a Zone object and changes some attribute of it.

Builders can be added to a given zone by specifying <builder>...</builder> tags in Worlds.xml. For example, the following snippet from Worlds.xml is used to build the zone for Kyakukya and the surrounding zones:

<cell Name="Kyakukya" Inherits="Jungle" ApplyTo="TerrainKyakukya" Mutable="false">
  <zone Level="5-9" x="0-2" y="0-2" Name="sky above Kyakukya" IndefiniteArticle="the">
    <builder Class="Sky"></builder>
  </zone>
  <zone Level="10" x="0-2" y="0-2" Name="outskirts" NameContext="Kyakukya" IndefiniteArticle="some" IncludeStratumInZoneDisplay="false" HasWeather="true" WindSpeed="0-60" WindDirections="N,NW,NW,W,W,SW,S,SE" WindDuration="50-3000">
    <population Table="Kyakukya Outskirts"></population>
  </zone>
  <zone Level="10" x="1" y="1" Name="Kyakukya" ProperName="true" IncludeStratumInZoneDisplay="false" HasWeather="true" WindSpeed="0-60" WindDirections="N,NW,NW,W,W,SW,S,SE" WindDuration="50-3000">
    <map FileName="Kyakukya.rpm"></map>
    <builder Class="Music" Track="Kyakukya" Chance="100"></builder>
    <builder Class="IsCheckpoint" Key="Kyakukya"></builder>
  </zone>
</cell>

This snippet includes several zone builders, such as

  • The Sky builder[1] is used to generate the zones over Kyakukya. This builder effectively does nothing other than add open air to every tile in the zone.
  • The Music builder[2] sets the music track that gets placed in Kyakukya
  • The IsCheckpoint builder[3] registers Kyakukya as a checkpoint for the game to auto-save, for games played in Roleplay or Wander mode.

To determine the builders that were used to generate a zone in-game, you can use the zonebuilders wish.

Creating a custom zone builder

Suppose that you had a custom terrain type called MyTerrain (see Modding:Maps), which you wanted to behave like a salt marsh with a large pit in the center (similar to Rust Wells). You could start by creating a Worlds.xml with the following contents (borrowed from WatervineCell):

<?xml version="1.0" encoding="utf-8" ?>
<worlds>
  <world Name="JoppaWorld" Load="Merge">

    <cell Name="MyName_MyMod_MyCell" Inherits="WatervineCell" ApplyTo="MyTerrain" Mutable="false" >
      <zone Level="10" x="1" y="1" Name="salt marsh" HasWeather="true" WindSpeed="0-50" WindDirections="N,NW,NW,W,W,SW,S,SE" WindDuration="200-3000" AmbientBed="Sounds/Ambiences/amb_bed_marsh" AmbientSounds="amb_scatter_marsh_bird1,amb_scatter_marsh_bird2,amb_scatter_marsh_insect1,amb_scatter_marsh_insect2">
        <builder Class="Watervine"></builder>
        <builder Class="FactionEncounters" Population="SafeFactionPopulation"></builder>
        <builder Class="Music" Track="Overworld1" Chance="10"></builder>
        <builder Class="ZoneTemplate:SaltMarsh"></builder>

        <!-- This is new! -->
        <builder Class="YourName_YourMod_PitBuilder"></builder>
      </zone>
      <zone Level="11-15" x="1" y="1" Name="subterranean salt marsh">
        <builder Class="Strata"></builder>
        <builder Class="Watervine" Underground="true"></builder>
        <builder Class="ZoneTemplate:WatervineCaves"></builder>
        <builder Class="FactionEncounters" Population="SafeFactionPopulation"></builder>
        <builder Class="Music" Track="Overworld1" Chance="10"></builder>

        <!-- This is new! -->
        <builder Class="YourName_YourMod_PitBuilder"></builder>
      </zone>
    </cell>
  </world>
</worlds>

In each zone, we add a new zone builder, YourName_YourMod_PitBuilder, implemented as follows:

using Genkit;

namespace XRL.World.ZoneBuilders {

    /// <summary>
    /// Custom ZoneBuilder that creates a large pit in the center of the zone, similar to
    /// the Rust Wells.
    /// </summary>
    public class YourName_YourMod_PitBuilder : ZoneBuilderSandbox
    {
        public bool BuildZone(Zone Z)
        {
            // Get center of map
            Point2D center = Location2D.get(40, 12).point;

            // Radius of pit is dependent on depth: radius=10 at Z=10, radius=4 at Z=15
            // Radius at each intermediate floor is determined by linearly interpolating between
            // these two values.
            float startFloor = 10f, endFloor = 15f;
            float startRadius = 10f, endRadius = 4f;
            float Radius = ((float)Z.Z - startFloor) * endRadius + (endFloor - (float)Z.Z) * startRadius;
            Radius = Radius / (endFloor - startFloor);

            foreach(Cell C in Z.GetCells())
            {
                if (C.CosmeticDistanceTo(center) > Radius)
                {
                    continue;
                }

                C.RemoveObjects((GameObject o) => true).ForEach(delegate(GameObject o)
                {
                    o.Obliterate();
                });
                C.Clear();
                C.AddObject("Pit");
            }

            Z.FireEvent("FirmPitEdges");
            ZoneBuilderSandbox.EnsureAllVoidsConnected(Z, pathWithNoise: true);

            return true;
        }
   }
}

This creates the zone shown below:

References

This information is reliable as of patch 2.0.204.92.
  1. XRL.World.ZoneBuilders.Sky
  2. XRL.World.ZoneBuilders.Music
  3. XRL.World.ZoneBuilders.IsCheckpoint