Source: mapgen/moisture.js

/**
 * Simulates the distribution of moisture across a world map.
 * Iterates through each row of the map, simulating the movement of a cloud that adjusts its moisture level based on the elevation of the cells it encounters.
 * The cloud's moisture level decreases when moving uphill and increases when moving downhill or over sea-level cells.
 * Tracks the number of mountains crossed and sets desert properties on cells based on moisture levels and position.
 */
function setMoisture() {
    for (let y = 0; y < world.height; y++) {
      let cloud = initializeCloud(y);
  
      while (cloud.x < world.width - 1) {
        let currentCell = xy(cloud.x, cloud.y);
        let nextCell = xy(cloud.x + 1, cloud.y);
  
        updateMoisture(cloud, currentCell, nextCell);
        adjustCloudForElevation(cloud, currentCell, nextCell);
        adjustCloudForMountains(cloud, currentCell, nextCell);
        markDesertAreas(cloud, nextCell);
  
        cloud.x += 1;
      }
    }
  }
  
  /**
   * Initializes a cloud object with initial properties.
   * 
   * @param {number} y - The y-coordinate of the row being processed.
   * @returns {Object} The initialized cloud object.
   */
  function initializeCloud(y) {
    return {
      x: 0,
      y: y,
      moisture: 50,
      mountainCount: 0
    };
  }
  
  /**
   * Updates the moisture level of the cloud based on the elevation difference between the current and next cell.
   * 
   * @param {Object} cloud - The cloud object.
   * @param {Object} currentCell - The current cell being processed.
   * @param {Object} nextCell - The next cell to be processed.
   */
  function updateMoisture(cloud, currentCell, nextCell) {
    currentCell.moisture = cloud.moisture;
    let elevationDiff = Math.floor(nextCell.elevation - currentCell.elevation);
  
    if (elevationDiff > 10) {
      cloud.moisture = Math.max(cloud.moisture - 1, 0);
    }
  
    if (nextCell.elevation <= limits.seaLevel.upper) {
      cloud.moisture += 1;
    }
  }
  
  /**
   * Adjusts the cloud's moisture level and mountain count based on the elevation of the current and next cell.
   * 
   * @param {Object} cloud - The cloud object.
   * @param {Object} currentCell - The current cell being processed.
   * @param {Object} nextCell - The next cell to be processed.
   */
  function adjustCloudForElevation(cloud, currentCell, nextCell) {
    let elevationDiff = Math.floor(nextCell.elevation - currentCell.elevation);
  
    if (nextCell.elevation > limits.mountains.lower) {
      cloud.mountainCount += 1;
      if (elevationDiff > 0) {
        cloud.moisture = Math.max(cloud.moisture - 1, 0);
        nextCell.moisture = cloud.moisture;
      }
    } else {
      cloud.mountainCount = Math.max(cloud.mountainCount - 1, 0);
    }
  }
  
  /**
   * Sets desert properties on cells based on the cloud's mountain count and the next cell's elevation.
   * 
   * @param {Object} cloud - The cloud object.
   * @param {Object} currentCell - The current cell being processed.
   * @param {Object} nextCell - The next cell to be processed.
   */
  function adjustCloudForMountains(cloud, currentCell, nextCell) {
    if (cloud.mountainCount > 0 && nextCell.elevation < limits.mountains.lower) {
      nextCell.desert = true;
    }
  }
  
  /**
   * Marks areas as desert based on the cloud's moisture level and position within the desert points.
   * 
   * @param {Object} cloud - The cloud object.
   * @param {Object} nextCell - The next cell to be processed.
   */
  function markDesertAreas(cloud, nextCell) {
    if (cloud.y > world.desertPointBottom + getRandomInt(1, 10) && 
        cloud.y < world.desertPointTop + getRandomInt(1, 10) && 
        cloud.moisture < 50) {
      nextCell.desert = true;
    } else {
      nextCell.desert = false;
    }
  }