-------- -- Simple weather controller: slot schedule, smooth type transition. -- Rain changes during the last seconds of the previous slot. -- Film follows rain, puddles follow film — both with linear rates. -------- local weatherUtils = require('shared/sim/weather') local humidityPresent = refbool(false) local pressurePresent = refbool(false) local cfg = ac.INIConfig.scriptSettings():mapSection('SETTINGS', { SLOTS = 3, SLOT_0 = 15, SLOT_1 = 15, SLOT_2 = 15, SLOT_3 = 15, SLOT_4 = 15, RANDOM = false, TIME_PER_SLOT = 5 }) -- ===== manual controls ====================================================== local TRANSITION_START = 0.5 -- type transition starts at this share of the slot local TRANSITION_MAX_S = 120 -- but never lasts longer than this, seconds local RAIN_RAMP_S = 20 -- rain changes during the last N seconds of the slot local RAIN_GAMMA = 3 -- ramp shape: slow start, sharp finish local WETNESS_MULT = 0.5 -- film target = rain * mult local WETNESS_GROW = 0.005 -- film growth per second at full rain (scales with rain) local WETNESS_DRY = 0.0002 -- film drying per second local WATER_MULT = 10.0 -- puddles target = film * mult local WATER_GROW = 0.02 -- puddles growth per second at full film (scales with film) local WATER_DRY = 0.0001 -- puddles drying per second -- ===== schedule ============================================================= local weatherTypes = {} for i = 1, math.clamp(cfg.SLOTS, 1, 10) do local weatherType = math.round(tonumber(cfg['SLOT_%d' % (i - 1)]) or ac.WeatherType.Clear) if weatherType < 0 or weatherType > 32 then weatherType = ac.WeatherType.Clear elseif weatherUtils.estimateRainIntensity(weatherType) > 0 then ac.preloadRainFX() end table.insert(weatherTypes, weatherType) end local conditions = ac.ConditionsSet() conditions.temperatures = ac.getInputTemperatures() conditions.wind = ac.getInputWind() conditions.humidity = ac.getInputHumidity(humidityPresent) conditions.pressure = ac.getInputPressure(pressurePresent) conditions.trackState = ac.getInputTrackState() local timePerSlotS = math.clamp(cfg.TIME_PER_SLOT, 1, 600) * 60 -- type transition window: last half of the slot, capped at TRANSITION_MAX_S local transitionStartS = math.max(timePerSlotS * TRANSITION_START, timePerSlotS - TRANSITION_MAX_S) local totalTimeS = 0 local slotIndex = 1 local wetness = 0 -- film on the road, 0..1 local water = 0 -- puddles, 0..1 -- move value toward target at a linear rate, no overshoot local function moveTo(value, target, rate, dt) if value < target then return math.min(value + rate * dt, target) end return math.max(value - rate * dt, target) end function script.update(dt) totalTimeS = totalTimeS + dt if totalTimeS > timePerSlotS then totalTimeS = 0 slotIndex = slotIndex % #weatherTypes + 1 end local nextIndex = slotIndex % #weatherTypes + 1 -- smooth type transition (visual only) conditions.currentType = weatherTypes[slotIndex] conditions.upcomingType = weatherTypes[nextIndex] conditions.transition = math.lerpInvSat(totalTimeS, transitionStartS, timePerSlotS) weatherUtils.setRoadTemperature(conditions) -- rain: holds current slot's value, then ramps to the next slot's value -- during the last RAIN_RAMP_S seconds; gamma = slow start, sharp finish local curRain = weatherUtils.estimateRainIntensity(weatherTypes[slotIndex]) local nextRain = weatherUtils.estimateRainIntensity(weatherTypes[nextIndex]) local ramp = math.lerpInvSat(totalTimeS, timePerSlotS - RAIN_RAMP_S, timePerSlotS) local rain = math.lerp(curRain, nextRain, math.pow(ramp, RAIN_GAMMA)) conditions.rainIntensity = rain -- film follows rain: linear growth (faster with stronger rain), linear drying local wetTarget = math.saturate(math.max(rain > 0.0001 and 0.01 or 0, rain * WETNESS_MULT)) local wetRate = wetness < wetTarget and WETNESS_GROW * rain or WETNESS_DRY wetness = moveTo(wetness, wetTarget, wetRate, dt) conditions.rainWetness = wetness -- puddles follow film the same way local waterTarget = math.saturate(wetness * WATER_MULT) local waterRate = water < waterTarget and WATER_GROW * wetness or WATER_DRY water = moveTo(water, waterTarget, waterRate, dt) conditions.rainWater = water ac.debug('slot', string.format('%d/%d: %s -> %s (%.0f%%)', slotIndex, #weatherTypes, weatherUtils.getWeatherName(weatherTypes[slotIndex]), weatherUtils.getWeatherName(weatherTypes[nextIndex]), conditions.transition * 100)) ac.debug('rain', string.format('%.3f (%.3f -> %.3f)', rain, curRain, nextRain)) ac.debug('wetness', string.format('%.3f -> %.3f', wetness, wetTarget)) ac.debug('water', string.format('%.3f -> %.3f', water, waterTarget)) ac.setConditionsSet2(conditions) end