w_point weather_generator::get_weather(const point &location, const calendar &t) const { const double x(location.x / 2000.0);// Integer x position / widening factor of the Perlin function. const double y(location.y / 2000.0);// Integer y position / widening factor of the Perlin function. // Leaving these in just in case something ELSE goes wrong--KA101 // int initial_season(0); // if(ACTIVE_WORLD_OPTIONS["INITIAL_SEASON"].getValue() == "spring") { // initial_season = 1; // } else if(ACTIVE_WORLD_OPTIONS["INITIAL_SEASON"].getValue() == "summer") { // initial_season = 2; // } else if(ACTIVE_WORLD_OPTIONS["INITIAL_SEASON"].getValue() == "autumn") { // initial_season = 3; // } const double z( double( t.get_turn() + DAYS(t.season_length()) ) / 2000.0); // Integer turn / widening factor of the Perlin function. const double dayFraction((double)t.minutes_past_midnight() / 1440); // Noise factors double T(raw_noise_4d(x, y, z, SEED) * 4.0); double H(raw_noise_4d(x, y, z / 5, SEED + 101)); double H2(raw_noise_4d(x, y, z, SEED + 151) / 4); double P(raw_noise_4d(x, y, z / 3, SEED + 211) * 70); double W; const double now( double( t.turn_of_year() + DAYS(t.season_length()) / 2 ) / double(t.year_turns()) ); // [0,1) const double ctn(cos(tau * now)); // Temperature variation const double mod_t(0); // TODO: make this depend on latitude and altitude? const double current_t(base_t + mod_t); // Current baseline temperature. Degrees Celsius. const double seasonal_variation(ctn * -1); // Start and end at -1 going up to 1 in summer. const double season_atenuation(ctn / 2 + 1); // Harsh winter nights, hot summers. const double season_dispersion(pow(2, ctn + 1) - 2.3); // Make summers peak faster and winters not perma-frozen. const double daily_variation(cos( tau * dayFraction - tau / 8 ) * -1 * season_atenuation / 2 + season_dispersion * -1); // Day-night temperature variation. T += current_t; // Add baseline to the noise. T += seasonal_variation * 8 * exp(-pow(current_t * 2.7 / 10 - 0.5, 2)); // Add season curve offset to account for the winter-summer difference in day-night difference. T += daily_variation * 8 * exp(-pow(current_t / 30, 2)); // Add daily variation scaled to the inverse of the current baseline. A very specific and finicky adjustment curve. T = T * 9 / 5 + 32; // Convert to imperial. =| // Humidity variation const double mod_h(0); const double current_h(base_h + mod_h); H = std::max(std::min((ctn / 10.0 + (-pow(H, 2) * 3 + H2)) * current_h / 2.0 + current_h, 100.0), 0.0); // Humidity stays mostly at the mean level, but has low peaks rarely. It's a percentage. // Pressure variation P += seasonal_variation * 20 + base_p; // Pressure is mostly random, but a bit higher on summer and lower on winter. In millibars. // Wind power W = std::max(0, 1020 - (int)P); return w_point {T, H, P, W, false}; }
// 4D Multi-octave Simplex noise. // // For each octave, a higher frequency/lower amplitude function will be added to the original. // The higher the persistence [0-1], the more of each succeeding octave will be added. float octave_noise_4d( const float octaves, const float persistence, const float scale, const float x, const float y, const float z, const float w ) { float total = 0; float frequency = scale; float amplitude = 1; // We have to keep track of the largest possible amplitude, // because each octave adds more, and we need a value in [-1, 1]. float maxAmplitude = 0; for( int i = 0; i < octaves; i++ ) { total += raw_noise_4d( x * frequency, y * frequency, z * frequency, w * frequency ) * amplitude; frequency *= 2; maxAmplitude += amplitude; amplitude *= persistence; } return total / maxAmplitude; }
// 4D Multi-octave Simplex noise. // // For each octave, a higher frequency/lower amplitude function will be added to the original. // The higher the persistence [0-1], the more of each succeeding octave will be added. double octave_noise_4d( const int octaves, const double persistence, const double scale, const double x, const double y, const double z, const double w ) { double total = 0; double frequency = scale; double amplitude = 1; // We have to keep track of the largest possible amplitude, // because each octave adds more, and we need a value in [-1, 1]. double maxAmplitude = 0; for( int i=0; i < octaves; i++ ) { total += raw_noise_4d( x * frequency, y * frequency, z * frequency, w * frequency ) * amplitude; frequency *= 2; maxAmplitude += amplitude; amplitude *= persistence; } return total / maxAmplitude; }
// 4D Scaled Simplex raw noise. // // Returned value will be between loBound and hiBound. double scaled_raw_noise_4d( const double loBound, const double hiBound, const double x, const double y, const double z, const double w ) { return raw_noise_4d(x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; }
// 4D Scaled Simplex raw noise. // // Returned value will be between loBound and hiBound. float scaled_raw_noise_4d( const float loBound, const float hiBound, const float x, const float y, const float z, const float w ) { return raw_noise_4d(x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; }
w_point weather_generator::get_weather( const tripoint &location, const time_point &t, unsigned seed ) const { const double x( location.x / 2000.0 ); // Integer x position / widening factor of the Perlin function. const double y( location.y / 2000.0 ); // Integer y position / widening factor of the Perlin function. const double z( to_turn<int>( t + calendar::season_length() ) / 2000.0 ); // Integer turn / widening factor of the Perlin function. const double dayFraction = time_past_midnight( t ) / 1_days; //limit the random seed during noise calculation, a large value flattens the noise generator to zero //Windows has a rand limit of 32768, other operating systems can have higher limits const unsigned modSEED = seed % 32768; // Noise factors double T( raw_noise_4d( x, y, z, modSEED ) * 4.0 ); double H( raw_noise_4d( x, y, z / 5, modSEED + 101 ) ); double H2( raw_noise_4d( x, y, z, modSEED + 151 ) / 4 ); double P( raw_noise_4d( x, y, z / 3, modSEED + 211 ) * 70 ); double A( raw_noise_4d( x, y, z, modSEED ) * 8.0 ); double W; const double now( ( time_past_new_year( t ) + calendar::season_length() / 2 ) / calendar::year_length() ); // [0,1) const double ctn( cos( tau * now ) ); // Temperature variation const double mod_t( 0 ); // TODO: make this depend on latitude and altitude? const double current_t( base_temperature + mod_t ); // Current baseline temperature. Degrees Celsius. const double seasonal_variation( ctn * -1 ); // Start and end at -1 going up to 1 in summer. const double season_atenuation( ctn / 2 + 1 ); // Harsh winter nights, hot summers. const double season_dispersion( pow( 2, ctn + 1 ) - 2.3 ); // Make summers peak faster and winters not perma-frozen. const double daily_variation( cos( tau * dayFraction - tau / 8 ) * -1 * season_atenuation / 2 + season_dispersion * -1 ); // Day-night temperature variation. T += current_t; // Add baseline to the noise. T += seasonal_variation * 8 * exp( -pow( current_t * 2.7 / 10 - 0.5, 2 ) ); // Add season curve offset to account for the winter-summer difference in day-night difference. T += daily_variation * 8 * exp( -pow( current_t / 30, 2 ) ); // Add daily variation scaled to the inverse of the current baseline. A very specific and finicky adjustment curve. T = T * 9 / 5 + 32; // Convert to imperial. =| // Humidity variation const double mod_h( 0 ); const double current_h( base_humidity + mod_h ); H = std::max( std::min( ( ctn / 10.0 + ( -pow( H, 2 ) * 3 + H2 ) ) * current_h / 2.0 + current_h, 100.0 ), 0.0 ); // Humidity stays mostly at the mean level, but has low peaks rarely. It's a percentage. // Pressure variation P += seasonal_variation * 20 + base_pressure; // Pressure is mostly random, but a bit higher on summer and lower on winter. In millibars. // Wind power W = std::max( 0, 1020 - static_cast<int>( P ) ); // Acid rains const double acid_content = base_acid * A; bool acid = acid_content >= 1.0; return w_point {T, H, P, W, acid}; }