123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- /*
- * Seven Kingdoms: Ancient Adversaries
- *
- * Copyright 1997,1998 Enlight Software Ltd.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- // Filename : OWEATHER.CPP
- // Description : class Weather
- // Ownership : Gilbert
- #include <OWEATHER.h>
- #include <ALL.h>
- #include <math.h>
- #include <OWORLDMT.h>
- //---------- Define constant -----------//
- #define RAIN_CLOUD 1
- #define LIGHTNING_CLOUD 2
- #define WINDY 4
- #define HOT_WAVE 8
- #define COLD_WAVE 0x10
- #define M_PI 3.14159265359
- //-------- Begin of function Lightning::rand_seed ----------//
- unsigned Weather::rand_seed(unsigned max)
- {
- #define MULTIPLIER 0x015a4e35L
- #define INCREMENT 1
- seed = MULTIPLIER * seed + INCREMENT;
- return seed % max;
- }
- //-------- End of function Lightning::rand_seed ----------//
- //---------- Begin of function Weather::init_date ----------//
- //
- void Weather::init_date(short year, short month, short day, short latitude, int quakeFreq)
- {
- // ----------- initialize random seed
- seed = 2*year+1;
- (void) rand_seed(10);
- // ----------- calculate season_phase from month, day ------------//
- season_phase = (short) ( month * 30.4 + day);
- season_phase = (season_phase + 365 - 98) % 365; // 7th Mar becomes 0
- // ----------- random number to earthquake -----------//
- quake_frequency = quakeFreq;
- day_to_quake = quakeFreq + rand_seed(quakeFreq);
- // ----------- determine avg_temp and temp_amp from latitude
- double angle = latitude * M_PI / 180.0;
- avg_temp = (short)( 35.0 - fabs(latitude / 90.0 * 40.0));
- temp_amp = (short)( 17.0 * sin(angle)); // negative for South Hemisphere
- // ----------- determine cloud ----------- //
- cur_cloud_str = rand_seed(4);
- cur_cloud_len = 5 + rand_seed(5);
- cur_cloud_type = 0;
- // ----------- determine wind ---------------//
- wind_dir = rand_seed(360);
- wind_spd = 10;
- high_wind_day = 0;
- windy_speed = 0;
- tornado_count = 1;
- }
- //---------- End of function Weather::init_date ----------//
- //---------- Begin of function Weather::next_day ----------//
- //
- void Weather::next_day()
- {
- season_phase = (season_phase + 1 )% 365;
- //---------- update/determine earthquake day ---------//
- if( day_to_quake)
- {
- day_to_quake--;
- if ( is_quake() )
- {
- // generate quake_x, quake_y
- quake_x = rand_seed(0x10000) * MAX_MAP_WIDTH / 0x10000;
- quake_y = rand_seed(0x10000) * MAX_MAP_HEIGHT / 0x10000;
- }
- }
- else
- day_to_quake = quake_frequency + rand_seed(quake_frequency);
- //---------- update wind ----------//
- wind_dir = (wind_dir + rand_seed(5) ) % 360;
- wind_spd += rand_seed(9) - 4 - (high_wind_day/16);
- if( wind_spd < -10)
- wind_spd = -10;
- if( wind_spd > 110)
- wind_spd = 110;
- if( wind_spd >= 20 )
- {
- high_wind_day++;
- }
- else
- {
- high_wind_day--;
- }
- //---------- generate cloud --------//
- if( cur_cloud_len > 0)
- {
- cur_cloud_len--;
- }
- else
- {
- short t = base_temp();
- short maxCloudStr;
- if( t >= 30)
- maxCloudStr = 10;
- else if( t <= 18)
- maxCloudStr = 4;
- else
- maxCloudStr = (t -18)/2 + 4;
- cur_cloud_str = rand_seed(maxCloudStr+4)-3; // range : -2 to maxCloudStr
- if(cur_cloud_str < 0)
- cur_cloud_str = 0;
- cur_cloud_len = 2 + rand_seed(3) + rand_seed(3);
- cur_cloud_type = 0;
-
- // ------- summer weather
- if( cur_cloud_str > 4)
- {
- if( (char) rand_seed(10) < cur_cloud_str )
- cur_cloud_type |= RAIN_CLOUD;
- if( cur_cloud_str >= 6 && (char) rand_seed(10) < cur_cloud_str-4)
- cur_cloud_type |= WINDY;
- }
- if( cur_cloud_str <= 1 && t >= 30 && rand_seed(10) <= 1)
- {
- cur_cloud_type |= HOT_WAVE;
- }
- // ------- winter weather
- if( t < 15)
- {
- if( rand_seed(20) < 2 )
- cur_cloud_type |= COLD_WAVE;
- if( t >= 10 && rand_seed(10) < 3)
- cur_cloud_type |= WINDY;
- if( t < 10 && rand_seed(10) < 7)
- cur_cloud_type |= WINDY;
- }
- if( cur_cloud_type & WINDY)
- windy_speed = 10 + cur_cloud_str * 5 + rand_seed(2*cur_cloud_str+1);
- else
- {
- windy_speed = 0;
- if( cur_cloud_str > 4 && (char)rand_seed(50) < cur_cloud_str + 2 )
- cur_cloud_type |= LIGHTNING_CLOUD;
- }
- // ---- double the time of snow ------ //
- if( snow_scale() )
- cur_cloud_len += cur_cloud_len;
- }
- // -------- update tornado_count, at least 20 days between two tornadoes -------//
- if( tornado_count > 20 && base_temp() >= 30 && wind_speed() >= 40
- && rand_seed(10)==0 )
- {
- tornado_count = 0; // today has a tornado
- }
- else
- {
- tornado_count++;
- }
- }
- //---------- End of function Weather::next_day ----------//
- //---------- Begin of function Weather::base_temp ----------//
- //
- short Weather::base_temp()
- {
- return( (short)(avg_temp + temp_amp * sin(season_phase / 365.0
- * 2 * M_PI) ));
- }
- //---------- End of function Weather::base_temp ----------//
- //---------- Begin of function Weather::cloud ----------//
- //
- short Weather::cloud()
- {
- if( cur_cloud_str < 0)
- return 0;
- if( cur_cloud_str > 10)
- return 10;
- return cur_cloud_str;
- }
- //---------- End of function Weather::cloud ----------//
- //---------- Begin of function Weather::temp_c ----------//
- //
- short Weather::temp_c()
- {
- return base_temp() - (cur_cloud_str < 1 ? 0 : (cur_cloud_str < 4 ? 2:4)) +
- (cur_cloud_type & HOT_WAVE ? 8:0) - (cur_cloud_type & COLD_WAVE ? 10:0);
- }
- //---------- End of function Weather::temp_c ----------//
- //---------- Begin of function Weather::temp_f ----------//
- //
- short Weather::temp_f()
- {
- return ((short) (base_temp() / 5.0 * 9.0 + 32.0 ));
- }
- //---------- End of function Weather::temp_f ----------//
- //---------- Begin of function Weather::wind_speed ----------//
- //
- short Weather::wind_speed()
- {
- if( this == &weather && magic_weather.wind_day > 0)
- return magic_weather.wind_speed();
- short w = wind_spd + windy_speed;
- if(w < 0)
- return 0;
- if(w > 100)
- return 100;
- return w;
- }
- //---------- End of function Weather::wind_speed ----------//
- //---------- Begin of function Weather::wind_direct ----------//
- //
- short Weather::wind_direct()
- {
- if( this == &weather && magic_weather.wind_day > 0)
- return magic_weather.wind_direct();
- return wind_dir;
- }
- //---------- End of function Weather::wind_direct ----------//
- //---------- Begin of function Weather::wind_direct_rad ----------//
- //
- double Weather::wind_direct_rad()
- {
- if( this == &weather && magic_weather.wind_day > 0)
- return magic_weather.wind_direct_rad();
- return wind_dir * M_PI / 180.0;
- }
- //---------- End of function Weather::wind_direct ----------//
- //---------- Begin of function Weather::rain_scale ----------//
- //
- short Weather::rain_scale()
- {
- if( this == &weather && magic_weather.rain_day > 0)
- return magic_weather.rain_scale();
- return cur_cloud_str > 4 ? cur_cloud_str * 2 -8 : 0;
- }
- //---------- End of function Weather::rain_scale ----------//
- //---------- Begin of function Weather::snow_scale ----------//
- //
- short Weather::snow_scale()
- {
- short t = temp_c();
- if( t > 0)
- return 0;
- if( t <= -15)
- {
- if( t <= -30)
- return 8;
- if( t <= -25)
- return 7;
- if( t <= -20)
- return 6;
- return 5;
- }
- else
- {
- if(t <= -10)
- return 4;
- if( t <= -5)
- return 3;
- if( t <= -2)
- return 2;
- return 1;
- }
- }
- //---------- End of function Weather::snow_scale ----------//
- //---------- Begin of function Weather::is_lightning ----------//
- //
- char Weather::is_lightning()
- {
- if( magic_weather.lightning_day > 0 )
- return LIGHTNING_CLOUD;
- return( cur_cloud_type & LIGHTNING_CLOUD );
- }
- //---------- End of function Weather::is_lightning ----------//
- //---------- Begin of function Weather::is_quake ----------//
- //
- char Weather::is_quake()
- {
- return( day_to_quake == 0);
- }
- //---------- End of function Weather::is_quake ----------//
- //---------- Begin of function Weather::desc ---------//
- //
- WeatherType Weather::desc()
- {
- int w = WEATHER_SUNNY;
- if( rain_scale() > 0 )
- w |= WEATHER_RAIN;
- if( is_lightning() )
- w |= WEATHER_LIGHTNING;
- if( snow_scale() > 0 )
- w |= WEATHER_SNOW;
- else if( cur_cloud_type & COLD_WAVE)
- w |= WEATHER_COLD_WAVE;
- if( cur_cloud_type & HOT_WAVE)
- w |= WEATHER_HOT_WAVE;
- if( cur_cloud_type & WINDY)
- w |= WEATHER_WINDY;
- if( w == WEATHER_SUNNY && cloud() >= 4)
- w |= WEATHER_CLOUDY;
- return (WeatherType)w;
- }
- //---------- End of function Weather::desc ---------//
- //---------- Begin of function Weather::has_tornado -------//
- char Weather::has_tornado()
- {
- return tornado_count == 0;
- }
- //---------- End of function Weather::has_tornado -------//
- //---------- Begin of function Weather::tornado_x_loc -------//
- //
- // return where a new tornado should create
- //
- short Weather::tornado_x_loc(short maxXLoc, short)
- {
- short dir = (wind_direct() + 180) % 360;
- err_when(dir < 0 || dir > 360);
- if( dir < 45)
- {
- // north side
- return maxXLoc*(dir+45)/90;
- }
- else if( dir < 135)
- {
- // east side
- return maxXLoc-1;
- }
- else if( dir < 225)
- {
- // south side
- return maxXLoc*(224-dir)/90;
- }
- else if( dir < 315)
- {
- // west side
- return 0;
- }
- else
- {
- // north side
- return maxXLoc*(dir-315)/90;
- }
- }
- //---------- End of function Weather::tornado_x_loc -------//
- //---------- Begin of function Weather::tornado_y_loc -------//
- short Weather::tornado_y_loc(short , short maxYLoc)
- {
- short dir = (wind_direct() + 180) % 360;
- err_when(dir < 0 || dir > 360);
- if( dir < 45)
- {
- // north side
- return 0;
- }
- else if( dir < 135)
- {
- // east side
- return maxYLoc*(dir-45)/90;
- }
- else if( dir < 225)
- {
- // south side
- return maxYLoc -1;
- }
- else if( dir < 315)
- {
- // west side
- return maxYLoc*(314-dir)/90;
- }
- else
- {
- // north side
- return 0;
- }
- }
- //---------- End of function Weather::tornado_y_loc -------//
- //---------- Begin of function Weather::quake_rate -------//
- short Weather::quake_rate(short x, short y)
- {
- err_when( !is_quake() );
- short dist = max( abs(x - quake_x), abs(y - quake_y) );
- short damage = 100 - dist / 2;
- return damage > 0 ? damage : 0;
- }
- //---------- End of function Weather::quake_rate -------//
- //--------- Begin of function MagicWeather::init ----------//
- void MagicWeather::init()
- {
- rain_day = 0;
- wind_day = 0;
- }
- //--------- End function MagicWeather::init ----------//
- //--------- Begin of function MagicWeather::next_day ----------//
- void MagicWeather::next_day()
- {
- if( rain_day > 0 )
- --rain_day;
- if( wind_day > 0 )
- --wind_day;
- if( lightning_day > 0 )
- --lightning_day;
- }
- //--------- End function MagicWeather::next_day ----------//
- //--------- Begin of function MagicWeather::cast_rain ----------//
- void MagicWeather::cast_rain(short duration, char rainScale)
- {
- // override last cast_rain
- rain_day = duration;
- rain_str = rainScale;
- }
- //--------- End of function MagicWeather::cast_rain ----------//
- //--------- Begin of function MagicWeather::cast_wind ----------//
- void MagicWeather::cast_wind(short duration, short speed, short direction)
- {
- // override last cast_wind
- wind_day = duration;
- wind_spd = speed;
- wind_dir = direction;
- }
- //--------- End of function MagicWeather::cast_wind ----------//
- //--------- Begin of function MagicWeather::cast_lightning ----------//
- void MagicWeather::cast_lightning(short duration)
- {
- // override last cast_lightning
- lightning_day = duration;
- }
- //--------- End of function MagicWeather::cast_lightning ----------//
- //--------- Begin of function MagicWeather::wind_speed ----------//
- short MagicWeather::wind_speed()
- {
- return wind_spd;
- }
- //--------- End of function MagicWeather::wind_speed ----------//
- //--------- Begin of function MagicWeather::wind_direct ----------//
- short MagicWeather::wind_direct()
- {
- return wind_dir;
- }
- //--------- End of function MagicWeather::wind_direct ----------//
- //--------- Begin of function MagicWeather::wind_direct_rad ----------//
- double MagicWeather::wind_direct_rad()
- {
- return wind_dir * M_PI / 180.0;
- }
- //--------- End of function MagicWeather::wind_direct_rad ----------//
- //--------- Begin of function MagicWeather::rain_scale ----------//
- short MagicWeather::rain_scale()
- {
- return rain_str;
- }
- //--------- End of function MagicWeather::rain_scale ----------//
|