Morwen's Weather Engine

From Infinite Worlds
Jump to navigation Jump to search

🌦️ Weather Engine Introduction[edit]

The Infinite Worlds Weather Engine simulates dynamic, realistic weather for your story world. It automatically tracks temperature, precipitation, wind, humidity, and visibility based on the current date and your location's climate configuration. Each weather state (sunny, rain, freezing rain, blizzard, etc.) has customizable properties including temperature modifiers, precipitation intensity, and humidity ranges. The system transitions between states using probability matrices, ensuring natural weather progression. Daily temperature variations come from seasonal base values, random noise, and weather-specific effects. Wind direction and speed add atmospheric realism. Weather updates whenever the date advances, with each state persisting for configurable durations. Special temperature constraints ensure physical accuracy, freezing rain only occurs below its minimum temperature threshold. Fully customizable for any setting, from tropical paradises to frozen tundras.

πŸ“‹ Weather Configuration Guide[edit]

This guide explains how to create your own weather configuration for the Infinite Worlds weather simulation system.

🎯 Overview[edit]

The weather config is a YAML-based tracked item that defines: Temperature patterns for your location Available weather states and their properties How weather transitions between states Wind, humidity, and other atmospheric conditions The system automatically updates weather based on date changes, ensuring realistic weather patterns for your world.

πŸ“ 1. Location Settings[edit]

location: "Portland, Oregon, USA"

location: Geographic location (affects temperature curves)

Purpose: Sets the context for temperature calculations.


πŸ“† 2. Monthly Configuration[edit]

months: 
  1:
    name: January 
    season: Winter
    base_temp: 5

Map of all months with the corresponding season and base_temp. base_temp is the average temperature of the month between daily and nightly temperatures.


🌑️ 2. Temperature Configuration[edit]

temperature:
  daily_amplitude: 5.0
  noise_scale: 1.5
  min: -5.0
  max: 20.0

daily_amplitude

  • Daily temperature swing (Β± from center)
  • 3-10Β°C

noise_scale

  • Random variation multiplier
  • 0.5-3.0

min

  • Absolute minimum temperature
  • -20 to 0Β°C

max

  • Absolute maximum temperature
  • 20-50Β°C

How Temperature Works

  • Final Temperature = Base + Noise + WeatherModifier Β± Amplitude/2
  • Base: Month-specific temperature from base_temp
  • Noise: Random variation (-noise_scale to +noise_scale)
  • WeatherModifier: Temperature adjustment from current weather state
  • Amplitude: Creates daily min/max range
  • Example: January (base=4.0), noise=+1.2, freezing_rain modifier=-1.0, amplitude=5.0
  • Center: 4.0 + 1.2 + (-1.0) = 4.2Β°C
  • Range: 4.2 Β± 2.5 = 1.7Β°C to 6.7Β°C


☁️ 3. Weather States[edit]

weather:
  states:
    sunny:
      prob: 0.05
      temp_mod: +2.0
      precip: 0.0
      humidity_range: [50, 65]
      description: "Clear skies"
      visibility: "excellent"
    
    freezing_rain:
      prob: 0.02
      temp_mod: -1.0
      precip: 3.0
      humidity_range: [90, 100]
      min_temp: -2.0
      description: "Freezing rain creating icy conditions"
      visibility: "poor"

prob

  • Base probability of this state (0-1)
  • 0.01-0.5

temp_mod

  • Temperature modifier for this state
  • -5 to +5Β°C

precip

  • Base precipitation intensity
  • 0-5

humidity_range

  • Min/max humidity percentage
  • [50, 95]

min_temp

  • Minimum required temperature (optional)
  • -10 to 10Β°C

description

  • Human-readable description
  • "Rain"

visibility

  • Visibility level
  • "excellent", "normal", "reduced", "poor", "whiteout"

Special Fields min_temp: Weather cannot persist if temperature rises above this value. Forces transition to another state.


πŸ”„ 4. Transition Matrix[edit]

transition_matrix:
  sunny:
    overcast: 0.60
    drizzle: 0.30
    sunny: 0.10
    
  overcast:
    sunny: 0.10
    drizzle: 0.35
    rain: 0.25
    fog: 0.10
    freezing_rain: 0.05
    blizzard: 0.02
    ice_fog: 0.05
    overcast: 0.08

[state]

  • Source weather state

[target_state]: probability

  • Probability of transitioning to target (0-1)

How It Works

  • Probabilities must sum to 1.0 for each source state
  • When weather duration expires, system rolls a random number (0-1)
  • Selects the first state where cumulative probability β‰₯ roll
  • Example: From overcast:
  • Roll 0.05 β†’ sunny (0.0-0.10)
  • Roll 0.25 β†’ drizzle (0.10-0.45)
  • Roll 0.75 β†’ rain (0.45-0.70)
  • Roll 0.95 β†’ ice_fog (0.90-0.95)


⏳ 5. Duration Settings[edit]

duration:
  sunny: {min: 2, max: 4}
  overcast: {min: 2, max: 8}
  drizzle: {min: 2, max: 12}
  rain: {min: 3, max: 8}

min

  • Minimum days this weather persists
  • 1-3

max

  • Maximum days this weather persists
  • 3-14

How It Works

  • When weather state begins, system rolls: random_between(min, max)
  • Weather persists until days_in_state β‰₯ rolled_value
  • Minimum of 2 ensures weather lasts at least 1 full day
  • Example: drizzle with min=2, max=12
  • Rolled duration: 5 days
  • Weather changes after 5+ days of drizzle


πŸ’¨ 6. Wind Configuration[edit]

wind:
  base_speed: 12.0
  dominant_direction: 225
  direction_variation: 45
  gust_probability: 0.10
  gust_multiplier: [1.5, 2.5]

base_speed

  • Average wind speed
  • km/h or mph

dominant_direction

  • Primary wind direction
  • Degrees (0-360)

direction_variation

  • Β± variation from dominant
  • Degrees

gust_probability

  • Chance of gusts (0-1)
  • 0-1

gust_multiplier

  • Wind speed multiplier during gusts
  • 1.0-3.0


How It Works

  • Final Wind Speed = BaseSpeed + Random(-4, +4) Γ— GustMultiplier
  • Final Direction = DominantDirection + Random(-Variation, +Variation)
  • Example: base=12, direction=225Β°, variation=45Β°
  • Speed: 12 + (-2) = 10 km/h
  • Direction: 225 + 10 = 235Β° (SW)
  • With gust (10% chance): 10 Γ— 1.8 = 18 km/h


πŸ’§ 7. Humidity Settings[edit]

humidity:
  range: [65, 95]

List[Number]

  • Min/max humidity percentage for the location

Note: Individual weather states can override this with their own humidity_range.


πŸ“Š Complete Example Configuration[edit]

Name: Weather Config

Type: YAML

Visibility: Hidden from both player and AI

Initial Value:

location: Your Location, Region
months: 
  1:
    name: January 
    season: Winter
    base_temp: 5
  2:
    name: February 
    season: Winter
    base_temp: 7
  3:
    name: March 
    season: Spring
    base_temp: 9
  4:
    name: April 
    season: Spring
    base_temp: 12
  5:
    name: May 
    season: Spring
    base_temp: 14
  6:
    name: June 
    season: Summer
    base_temp: 18
  7:
    name: July 
    season: Summer
    base_temp: 20
  8:
    name: August 
    season: Summer
    base_temp: 20
  9:
    name: September 
    season: Autumn 
    base_temp: 18
  10:
    name: October 
    season: Autumn
    base_temp: 13
  11:
    name: November 
    season: Autumn
    base_curve: 9
  12:
    name: December 
    season: winter
    base_temp: 6
  
temperature:
  daily_amplitude: 5.0
  noise_scale: 1.5
  min: -5.0
  max: 30.0

weather:
  states:
    sunny:
      prob: 0.05
      temp_mod: +2.0
      precip: 0.0
      humidity_range: [50, 65]
      description: Clear skies
      visibility: excellent
    overcast:
      prob: 0.30
      temp_mod: 0.0
      precip: 0.0
      humidity_range: [70, 80]
      description: Cloudy
      visibility: normal
    drizzle:
      prob: 0.40
      temp_mod: -1.0
      precip: 0.5
      humidity_range: [80, 90]
      description: Light drizzle
      visibility: reduced
    rain:
      prob: 0.20
      temp_mod: -2.0
      precip: 2.0
      humidity_range: [85, 95]
      description: Rain
      visibility: reduced
    snow:
      prob: 0.05
      temp_mod: -3.0
      precip: 1.0
      humidity_range: [75, 85]
      min_temp: -5.0
      description: Snow
      visibility: poor
    fog:
      prob: 0.05
      temp_mod: 0.0
      precip: 0.0
      humidity_range: [95, 100]
      description: Fog
      visibility: poor
    freezing_rain:
      prob: 0.02
      temp_mod: -1.0
      precip: 3.0
      humidity_range: [90, 100]
      min_temp: -2.0
      description: Freezing rain creating icy conditions
      visibility: poor
    blizzard:
      prob: 0.01
      temp_mod: -5.0
      precip: 4.0
      humidity_range: [80, 90]
      min_temp: -5.0
      description: Blizzard with strong winds and heavy snow
      visibility: whiteout
    ice_fog:
      prob: 0.02
      temp_mod: -2.0
      precip: 0.0
      humidity_range: [98, 100]
      min_temp: -2.0
      description: Dense ice fog with freezing temperatures
      visibility: whiteout

  transition_matrix:
    sunny: {overcast: 0.60, drizzle: 0.30, sunny: 0.10}
    overcast: {sunny: 0.10, drizzle: 0.35, rain: 0.25, fog: 0.10, freezing_rain: 0.05, blizzard: 0.02, ice_fog: 0.05, overcast: 0.08}
    drizzle: {overcast: 0.30, rain: 0.35, sunny: 0.10, freezing_rain: 0.05, drizzle: 0.20}
    rain: {drizzle: 0.35, overcast: 0.35, rain: 0.15, snow: 0.05, freezing_rain: 0.10}
    snow: {overcast: 0.30, rain: 0.30, snow: 0.25, blizzard: 0.10, freezing_rain: 0.05}
    fog: {overcast: 0.50, drizzle: 0.30, fog: 0.10, ice_fog: 0.10}
    freezing_rain: {overcast: 0.40, rain: 0.20, snow: 0.30, ice_fog: 0.10}
    blizzard: {snow: 0.60, overcast: 0.40}
    ice_fog: {fog: 0.50, overcast: 0.50}

  duration:
    sunny: {min: 1, max: 4}
    overcast: {min: 2, max: 8}
    drizzle: {min: 2, max: 12}
    rain: {min: 3, max: 8}
    snow: {min: 2, max: 6}
    fog: {min: 1, max: 4}
    freezing_rain: {min: 1, max: 3}
    blizzard: {min: 1, max: 2}
    ice_fog: {min: 1, max: 2}

wind:
  base_speed: 12.0
  dominant_direction: 225
  direction_variation: 45
  gust_probability: 0.10
  gust_multiplier: [1.5, 2.5]

humidity:
  range: [65, 95]

πŸ’‘ Configuration Tips[edit]

Temperature Tips

  • base_temp: Research average monthly temperatures for your location
  • amplitude: Higher = more daily variation (desert: 10-15Β°C, coastal: 3-5Β°C)
  • noise_scale: Higher = more unpredictable weather (0.5 = stable, 3.0 = chaotic)
  • min/max: Set absolute bounds (e.g., -20Β°C to 40Β°C)

Weather State Tips

  • prob: Sum of all probs should be ~1.0 (but not required)
  • temp_mod: Negative for cold weather, positive for warm
  • min_temp: Use for weather that requires specific temperatures (snow, freezing_rain)
  • precip: 0 = none, 1-2 = light, 3-4 = moderate, 5 = heavy

Transition Matrix Tips

  • Self-transitions: Include the state itself (e.g., sunny: 0.10) for stability
  • Realism: Common transitions should have higher probabilities
  • Sum to 1.0: Each state's probabilities must sum to exactly 1.0

Duration Tips

  • Short-lived: Storms, blizzards (1-3 days)
  • Medium: Rain, snow (2-8 days)
  • Long: Drought, heat waves (7-14 days)
  • Always use min: 2 to ensure at least 1 full day

Wind Tips

  • direction: 0=N, 90=E, 180=S, 270=W
  • variation: 0 = consistent direction, 90 = highly variable
  • gust_probability: 0.05-0.20 for occasional gusts

πŸ”§ Debugging Your Config[edit]

Common Issues: Weather never changes

  • Check duration.min values (should be β‰₯ 2)
  • Verify days_passed is being set by AI
  • Ensure transition_matrix probabilities sum to 1.0

Temperature too extreme

  • Reduce noise_scale
  • Adjust base_curve values
  • Widen min/max bounds

Weather changes too frequently

  • Increase duration.min and duration.max
  • Reduce transition probabilities to other states

Wrong weather for temperature

  • Add min_temp to cold weather states
  • Adjust temp_mod values

Wind always from same direction

  • Increase direction_variation
  • Check dominant_direction value

Other Tracked Items[edit]

Weather State[edit]

Name: Weather State

Type: YAML

Description: Current weather conditions

Visibility: At least visible to AI

Update instructions: Automatically update tracked item = unchecked

Initial Value:

temperature_unit: degree Celcius
current: freezing_rain
temperature_min: -3.0
temperature_max: 2.0
precipitation: 3.0
humidity: 95
wind_speed: 15.0
wind_direction: 225
wind_description: from the SW
description: Freezing rain creating icy conditions
visibility: poor
season: winter
last_updated: 0
days_in_state: 0

Current Date[edit]

Name: Current Date

Type: YAML

Description: Current date based on whereWhenAfter. Update this when player advances time through choices.

Visibility: At least visible to AI

Update instructions: Update year, month, day, days_passed as time passes. Set day_changed to true when the day changes. Compare to whereWhenAfter.

Example:

year: 2026
month: 10
day: 15
day_changed: 'false'
days_passed: 2
season: autumn

Enforce sticking to this format: checked Initial Value:

year: 2026
month: 10
day: 15
day_changed: 'false'
days_passed: 0
season: autumn

Weather Engine Trigger[edit]

Name: Any

Select β€œAllow triggering multiple times”

Condition: Turn number at least β€œ1”

Effects: Run a script

# Only update weather when days have passed
if $current_date.days_passed > 0

  # === TEMPERATURE CALCULATION (daily) ===
  # Get base temperature for current month (1-12)
  set $base_temp = $weather_config.months.item($current_date.month).base_temp
  $weather_state.season = $weather_config.months.item($current_date.month).season

  # Daily noise
  set $noise = (random() - 0.5) * 2 * $weather_config.temperature.noise_scale

  # Get current weather config using .item()
  set $weather_section = $weather_config.item('weather')
  set $states = $weather_section.item('states')
  set $weather_cfg = $states.item($weather_state.current)

  # Calculate temperature range WITH weather modifier
  set $temp_center = $base_temp + $noise + $weather_cfg.temp_mod
  set $temp_min = ($temp_center - $weather_config.temperature.daily_amplitude / 2).constrain($weather_config.temperature.min, $weather_config.temperature.max).round(1)
  set $temp_max = ($temp_center + $weather_config.temperature.daily_amplitude / 2).constrain($weather_config.temperature.min, $weather_config.temperature.max).round(1)

  # === ENFORCE CURRENT WEATHER TEMPERATURE CONSTRAINTS ===
  set $current_min_temp = $weather_cfg.item('min_temp', 100)
  if $current_min_temp and $temp_max < $current_min_temp
    set $force_transition = true
  else if $current_min_temp and $temp_min > $current_min_temp
    set $force_transition = true
  else
    set $force_transition = false

  if $force_transition
    # Force immediate transition
    set $current_weather = $weather_state.current
    set $transitions_matrix = $weather_section.item('transition_matrix')
    set $transitions = $transitions_matrix.item($current_weather)
    set $roll = random()
    set $cumulative = 0
    set $next_weather = $current_weather
    set $found = false

    for each $state_name in $transitions.keys()
      if not $found
        set $prob = $transitions.item($state_name)
        set $cumulative = $cumulative + $prob
        if $roll < $cumulative
          set $next_weather = $state_name
          set $found = true

    set $next_cfg = $states.item($next_weather)
    set $temp_ok = true

    set $next_min_temp = $next_cfg.item('min_temp', 100)
    if $next_min_temp and $temp_min > $next_min_temp
      set $temp_ok = false

    if $next_weather != $current_weather and $temp_ok
      $weather_state.current = $next_weather
      $weather_state.temperature_min = $temp_min
      $weather_state.temperature_max = $temp_max
  else
    # === NORMAL WEATHER STATE TRANSITIONS ===
    set $current_weather = $weather_state.current

    # Use days_in_state if it exists, otherwise initialize
    if not $weather_state.days_in_state
      $weather_state.days_in_state = 0

    # Accumulate days in current state
    $weather_state.days_in_state = $weather_state.days_in_state + $current_date.days_passed

    set $durations = $weather_section.item('duration')
    set $dur_min = $durations.item($current_weather).item('min')
    set $dur_max = $durations.item($current_weather).item('max')

    # Check if accumulated days meets or exceeds target duration
    if $weather_state.days_in_state >= random_between($dur_min, $dur_max)
      set $transitions_matrix = $weather_section.item('transition_matrix')
      set $transitions = $transitions_matrix.item($current_weather)
      set $roll = random()
      set $cumulative = 0
      set $next_weather = $current_weather
      set $found = false

      for each $state_name in $transitions.keys()
        if not $found
          set $prob = $transitions.item($state_name)
          set $cumulative = $cumulative + $prob
          if $roll < $cumulative
            set $next_weather = $state_name
            set $found = true

      set $next_cfg = $states.item($next_weather)
      set $temp_ok = true

      set $next_min_temp = $next_cfg.item('min_temp', 100)
      if $next_min_temp and $temp_min > $next_min_temp
        set $temp_ok = false

      if $next_weather != $current_weather and $temp_ok
        $weather_state.current = $next_weather
        $weather_state.days_in_state = 0  # Reset counter on state change
        $weather_state.last_updated = $game.turn_number

    $weather_state.temperature_min = $temp_min
    $weather_state.temperature_max = $temp_max

  # === PRECIPITATION & HUMIDITY ===
  set $current_cfg = $states.item($weather_state.current)

  if $current_cfg.precip > 0
    $weather_state.precipitation = ($current_cfg.precip * (0.8 + random() * 0.4)).round(1)
  else
    $weather_state.precipitation = 0

  $weather_state.humidity = random_between($current_cfg.humidity_range.item(1), $current_cfg.humidity_range.item(2))

  # === WIND SIMULATION ===
  $weather_state.wind_speed = $weather_config.wind.base_speed + random_between(0, 8) - 4

  set $dir_var = random_between(0, $weather_config.wind.direction_variation * 2) - $weather_config.wind.direction_variation
  $weather_state.wind_direction = ($weather_config.wind.dominant_direction + $dir_var) % 360

  set $directions = list('N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW')
  set $index = ($weather_state.wind_direction / 45).round() % 8
  $weather_state.wind_description = 'from the ' & $directions.item($index + 1)

  if random() < $weather_config.wind.gust_probability
    set $gust_mult_min = $weather_config.wind.gust_multiplier.item(1)
    set $gust_mult_max = $weather_config.wind.gust_multiplier.item(2)
    set $gust_mult = random_between($gust_mult_min * 100, $gust_mult_max * 100) / 100.0
    $weather_state.wind_speed = $weather_state.wind_speed * $gust_mult

  if $weather_state.wind_speed < 0
    $weather_state.wind_speed = 0

  # === DESCRIPTIONS ===
  $weather_state.description = $current_cfg.description
  $weather_state.visibility = $current_cfg.visibility

  # Reset days_passed after processing
  $current_date.days_passed = 0
  $current_date.day_changed = 'false'