Obscurities Weather System
--------------------------

Original Weather code from the Obscurities codebase.
Modified for Smaug compatibility by Kayle of Malevolent Whispers.
Adapted for use in AFKMud by Samson.

Terms of Use
------------

1. You may use this snippet in your code provided that any included
comment headers in the code are left intact. You may add your own, but
do not take mine out.

2. This snippet may not be posted for redistribution on any site
without obtaining prior written consent from me.

If you can't agree to these terms, don't use this code, and don't expect
me to help if something breaks while installing it. 

What this code does
-------------------

This code replaces the stock weather system with more diverse and readily expandable
systems.

The weather system completely revises how weather in AFKMud is handled. It uses
an influence map to account for all neighboring cells, and allows for all cells
to influence one another based on snapshots taken at the time of update. Messages
describing the weather are more fluid, describing changes in the amount of 
precipitation, cloud cover, or temperature. These messages are easily expandable
to include the other monitored values for each cell. Also, Climate controllers can
be applied to certain cells to prevent the weather from reaching equilibrium, the
point where all cells and all values within those cells are equal. In addition to
climate, hemisphere flags can be applied to each cell as well. In conjunction with
the climate flags, the hemisphere flags will effectively reverse the weather patterns
for the seasons, so that summer in the southern hemisphere produces frigid temperatures
and snow, while the northern would produce heat and rain. The system is about as 
encapsulated as C++ will allow, functions have been provided, and several examples 
have been placed thoughout the code to showcase how to interact with the system through
those provided function.

Installation Instructions
-------------------------

1. The following files will be modified during the course of this installation:

	act_info.cpp, area.cpp, area.h, area_fussconvert.cpp, area_oldafk.cpp, areaconvert.cpp,
	comm.cpp, const.cpp, db.cpp, magic.cpp, mspecial.cpp, overland.cpp,
	update.cpp, and mud.h.

   The following 2 files will be added to the game. Copy those to your src folder now.
   
    weather.cpp, weather.h

****************
* ACT_INFO.CPP *
****************

2. Find:

#include "sha256.h"

Below that, add:

#include "weather.h"

3. In void look_sky( char_data * ch ), find:

   int starpos, sunpos, moonpos, moonphase, i, linenum, precip;

   ch->pager( "You gaze up towards the heavens and see:\r\n" );

   precip = ( ch->in_room->area->weather->precip + 3 * weath_unit - 1 ) / weath_unit;
   if( precip > 1 )
   {
      ch->print( "There are some clouds in the sky so you cannot see anything else.\r\n" );
      return;
   }

Replace it with:

   int starpos, sunpos, moonpos, moonphase, i, linenum;
   WeatherCell *cell = getWeatherCell( ch->in_room->area );

   ch->pager( "You gaze up towards the heavens and see:\r\n" );

   if( isModeratelyCloudy( getCloudCover( cell ) ) )
   {
      ch->print( "There are too many clouds in the sky so you cannot see anything else.\r\n" );
      return;
   }

Find and remove the do_weather function.

****************
* AREA.CPP     *
****************

4. At the top, below the include for shops.h, add:

#include "weather.h"

3. Find the following, and remove it:

neighbor_data::neighbor_data(  )
{
   address = nullptr;
}

neighbor_data::~neighbor_data(  )
{
}

weather_data::weather_data(  )
{
   init_memory( &temp, &echo_color, sizeof( echo_color ) );
   neighborlist.clear(  );
}

weather_data::~weather_data(  )
{
   list < neighbor_data * >::iterator neigh;

   for( neigh = neighborlist.begin(  ); neigh != neighborlist.end(  ); )
   {
      neighbor_data *neighbor = *neigh;
      ++neigh;

      neighborlist.remove( neighbor );
      deleteptr( neighbor );
   }
}

5. In area_data::~area_data(  ), find the following and remove it:

   if( weather )
      deleteptr( weather );
	  
6. Find:

area_data::area_data(  )
{
   init_memory( &weather, &tg_armor, sizeof( tg_armor ) );
}

Change it to read as:

area_data::area_data(  )
{
   init_memory( &continent, &tg_armor, sizeof( tg_armor ) );
}

7. In area_data *create_area( void ), find and remove the following:

   /*
    * initialize weather data - FB 
    */
   pArea->weather = new weather_data;
   pArea->weather->climate_temp = 2;
   pArea->weather->climate_precip = 2;
   pArea->weather->climate_wind = 2;
   pArea->weather->echo_color = AT_GREY;
   
Replace it with:

   pArea->weatherx = 0;
   pArea->weathery = 0;

8. In void fread_afk_areadata( FILE * fp, area_data * tarea ), find the following:

            if( !str_cmp( word, "Climate" ) )
            {
               tarea->weather->climate_temp = fread_number( fp );
               tarea->weather->climate_precip = fread_number( fp );
               tarea->weather->climate_wind = fread_number( fp );
               break;
            }

Replace it with:

            if( !str_cmp( word, "Climate" ) )
            {
               // These values are no longer used with the new weather code.
               fread_to_eol( fp );
               break;
            }

Then find:

            if( !str_cmp( word, "Neighbor" ) )
            {
               neighbor_data *anew;

               anew = new neighbor_data;
               anew->address = nullptr;
               fread_string( anew->name, fp );
               tarea->weather->neighborlist.push_back( anew );
               break;
            }

Replace it with:

            if( !str_cmp( word, "Neighbor" ) )
            {
               // This section is no longer used with the new weather code.
               fread_to_eol( fp );
               break;
            }

Then find:

                  else
                  {
                     /*
                      * Clean out the old resets
                      */
                     log_printf_plus( LOG_BUILD, sysdata->build_level, "Cleaning resets: %s", tarea->name );
                     pRoomIndex->clean_resets(  );
                  }
               }
               break;
            }
            break;

Below that, add:

         case 'W':
            if( !str_cmp( word, "WeatherCoords" ) )
            {
               tarea->weatherx = fread_number( fp );
               tarea->weathery = fread_number( fp );
            }
            break;

9. In void fwrite_area_header( area_data * area, FILE * fpout ), find the following and remove it:

   fprintf( fpout, "Climate         %d %d %d\n", area->weather->climate_temp, area->weather->climate_precip, area->weather->climate_wind );

   /*
    * neighboring weather systems - FB 
    */
   list < neighbor_data * >::iterator neigh;
   for( neigh = area->weather->neighborlist.begin(  ); neigh != area->weather->neighborlist.end(  ); ++neigh )
   {
      neighbor_data *nb = *neigh;
      fprintf( fpout, "Neighbor           %s~\n", nb->name.c_str(  ) );
   }

Replace it with:

   fprintf( fpout, "WeatherCoords   %d %d\n\n", area->weatherx, area->weathery );

10. Find and remove the following functions:

void init_area_weather( void )
void load_weatherdata( void )
void save_weatherdata( void )
CMDF( do_setweather )
CMDF( do_showweather )
CMDF( do_climate )

11. In CMDF( do_astat ), find the following:

   if( tarea->continent )
      ch->printf( "&wContinent or Plane: &W%s\r\n", tarea->continent->name.c_str( ) );
   else
      ch->print( "&wContinent or Plane: &W<NOT SET>\r\n" );

   ch->printf( "&wCoordinates: &W%d %d\r\n", tarea->map_x, tarea->map_y );

Below that, add:

   ch->printf( "&wWeather: X Coord: &W%-3d  &w Y Coord: &W%-3d\r\n", tarea->weatherx, tarea->weathery );

12. In CMDF( do_aset ), find the following:

      ch->print( "  author credits resetmsg resetfreq flags\r\n" );

Below that, add:

      ch->print( "  weatherx weathery\r\n" );

Then find:

   if( !str_cmp( arg2, "coords" ) )
   {
      int x, y;

      argument = one_argument( argument, arg3 );

      if( arg3[0] == '\0' || argument[0] == '\0' )
      {
         ch->print( "You must specify X and Y coordinates for this.\r\n" );
         return;
      }

      x = atoi( arg3.c_str(  ) );
      y = atoi( argument.c_str(  ) );

      if( !is_valid_x( x ) )
      {
         ch->printf( "Valid X coordinates are from 0 to %d.\r\n", MAX_X - 1 );
         return;
      }

      if( !is_valid_y( y ) )
      {
         ch->printf( "Valid Y coordinates are from 0 to %d.\r\n", MAX_Y - 1 );
         return;
      }

      tarea->map_x = x;
      tarea->map_y = y;

      ch->print( "Area coordinates set.\r\n" );
      return;
   }

Below that, add:

   if( !str_cmp( arg2, "weatherx" ) )
   {
      tarea->weatherx = vnum;
      ch->print( "Weather X Coordinate set.\r\n" );
      return;
   }

   if( !str_cmp( arg2, "weathery" ) )
   {
      tarea->weathery = vnum;
      ch->print( "Weather Y Coordinate set.\r\n" );
      return;
   }

****************
* AREA.H       *
****************

13. Find and remove:

class neighbor_data
{
 private:
   neighbor_data( const neighbor_data & n );
     neighbor_data & operator=( const neighbor_data & );

 public:
     neighbor_data(  );
    ~neighbor_data(  );

   area_data *address;
   string name;
};

/* Define maximum number of climate settings - FB */
const int MAX_CLIMATE = 5;

class weather_data
{
 private:
   weather_data( const weather_data & w );
     weather_data & operator=( const weather_data & );

 public:
     weather_data(  );
    ~weather_data(  );

     list < neighbor_data * >neighborlist;   /* areas which affect weather sys */
   string echo;   /* echo string */
/*   int mmhg;
   int change;
   int sky;
   int sunlight; */
   int temp;   /* temperature */
   int precip; /* precipitation */
   int wind;   /* umm... wind */
   int temp_vector;  /* vectors controlling */
   int precip_vector;   /* rate of change */
   int wind_vector;
   int climate_temp; /* climate of the area */
   int climate_precip;
   int climate_wind;
   int echo_color;   /* color for the echo */
};

14. In class area_data, find and remove:

   weather_data *weather;           /* FB */

Then below:

   int low_hard_range;
   int hi_hard_range;
   
Add:

   short weatherx;                  // X Coordinate for this area's weather data.
   short weathery;                  // Y Coodrinate for this area'a weather data.

**************************
* AREA_FUSSCONVERT.CPP   *
**************************

15. In void fread_fuss_areadata( FILE * fp, area_data * tarea ), find:

         case 'V':
            KEY( "Version", tarea->version, fread_number( fp ) );
            break;

Below that, add:

         case 'W':
            KEY( "WeatherX", tarea->weatherx, fread_number( fp ) );
            KEY( "WeatherY", tarea->weathery, fread_number( fp ) );
            break;

*********************
* AREA_OLDAFK.CPP   *
*********************

16. In bool load_oldafk_area( FILE *fpArea, area_data *tarea, int area_version ), find:

      else if( !str_cmp( word, "CLIMATE" ) )
      {
         tarea->weather->climate_temp = fread_number( fpArea );
         tarea->weather->climate_precip = fread_number( fpArea );
         tarea->weather->climate_wind = fread_number( fpArea );
      }

Replace it with:

      else if( !str_cmp( word, "CLIMATE" ) )
      {
         // These values are ignored with the new weather code.
         fread_to_eol( fpArea );
      }

Then find:

      else if( !str_cmp( word, "NEIGHBOR" ) )
      {
         neighbor_data *anew;

         anew = new neighbor_data;
         anew->address = nullptr;
         anew->name = fread_string( fpArea );
         tarea->weather->neighborlist.push_back( anew );
      }

Replace it with:

      else if( !str_cmp( word, "NEIGHBOR" ) )
      {
         // This section is no longer used with the new weather code.
         fread_to_eol( fpArea );
      }

*********************
* AREACONVERT.CPP   *
*********************

17. In void load_stock_area_file( const string & filename, bool manual ), find:

      else if( !str_cmp( word, "CLIMATE" ) )
      {
         const char *ln;
         int x1, x2, x3, x4;

         if( dotdcheck > 0 && dotdcheck < 4 )
         {
            bug( "DOTDII area encountered with invalid header format, check value %d", dotdcheck );
            shutdown_mud( "Invalid DOTDII area" );
            exit( 1 );
         }

         ln = fread_line( fpArea );
         x1 = x2 = x3 = x4 = 0;
         sscanf( ln, "%d %d %d %d", &x1, &x2, &x3, &x4 );

         tarea->weather->climate_temp = x1;
         tarea->weather->climate_precip = x2;
         tarea->weather->climate_wind = x3;
      }
      else if( !str_cmp( word, "NEIGHBOR" ) )
      {
         neighbor_data *anew;

         anew = new neighbor_data;
         anew->address = nullptr;
         anew->name = fread_string( fpArea );
         tarea->weather->neighborlist.push_back( anew );
      }

Replace it with:

      else if( !str_cmp( word, "CLIMATE" ) )
      {
         if( dotdcheck > 0 && dotdcheck < 4 )
         {
            bug( "DOTDII area encountered with invalid header format, check value %d", dotdcheck );
            shutdown_mud( "Invalid DOTDII area" );
            exit( 1 );
         }

         fread_line( fpArea );

         // Climate values are no longer used with the new weather code.
      }
      else if( !str_cmp( word, "NEIGHBOR" ) )
      {
         fread_line( fpArea );

         // This section is no longer used with the new weather code.
      }

**************
* COMM.CPP   *
**************

18. Find:

void save_ships(  );
void save_timedata(  );

Below that, add:

void save_weathermap(  );

19. In void close_mud( void ), find:

   log_string( "Saving game world time...." );
   save_timedata(  );

Below that, add:

   log_string( "Saving weather map data..." );
   save_weathermap(  );


*****************
* CONST.CPP     *
*****************

20. Find and remove the following:

/* Weather constants - FB */
const char *temp_settings[MAX_CLIMATE] = {
   "cold",
   "cool",
   "normal",
   "warm",
   "hot",
};

const char *precip_settings[MAX_CLIMATE] = {
   "arid",
   "dry",
   "normal",
   "damp",
   "wet",
};

const char *wind_settings[MAX_CLIMATE] = {
   "still",
   "calm",
   "normal",
   "breezy",
   "windy",
};

const char *preciptemp_msg[6][6] = {
   /*
    * precip = 0 
    */
   {
    "Frigid temperatures settle over the land",
    "It is bitterly cold",
    "The weather is crisp and dry",
    "A comfortable warmth sets in",
    "A dry heat warms the land",
    "Seething heat bakes the land"},
   /*
    * precip = 1 
    */
   {
    "A few flurries drift from the high clouds",
    "Frozen drops of rain fall from the sky",
    "An occasional raindrop falls to the ground",
    "Mild drops of rain seep from the clouds",
    "It is very warm, and the sky is overcast",
    "High humidity intensifies the seering heat"},
   /*
    * precip = 2 
    */
   {
    "A brief snow squall dusts the earth",
    "A light flurry dusts the ground",
    "Light snow drifts down from the heavens",
    "A light drizzle mars an otherwise perfect day",
    "A few drops of rain fall to the warm ground",
    "A light rain falls through the sweltering sky"},
   /*
    * precip = 3 
    */
   {
    "Snowfall covers the frigid earth",
    "Light snow falls to the ground",
    "A brief shower moistens the crisp air",
    "A pleasant rain falls from the heavens",
    "The warm air is heavy with rain",
    "A refreshing shower eases the oppresive heat"},
   /*
    * precip = 4 
    */
   {
    "Sleet falls in sheets through the frosty air",
    "Snow falls quickly, piling upon the cold earth",
    "Rain pelts the ground on this crisp day",
    "Rain drums the ground rythmically",
    "A warm rain drums the ground loudly",
    "Tropical rain showers pelt the seering ground"},
   /*
    * precip = 5 
    */
   {
    "A downpour of frozen rain covers the land in ice",
    "A blizzard blankets everything in pristine white",
    "Torrents of rain fall from a cool sky",
    "A drenching downpour obscures the temperate day",
    "Warm rain pours from the sky",
    "A torrent of rain soaks the heated earth"}
};

const char *windtemp_msg[6][6] = {
   /*
    * wind = 0 
    */
   {
    "The frigid air is completely still",
    "A cold temperature hangs over the area",
    "The crisp air is eerily calm",
    "The warm air is still",
    "No wind makes the day uncomfortably warm",
    "The stagnant heat is sweltering"},
   /*
    * wind = 1 
    */
   {
    "A light breeze makes the frigid air seem colder",
    "A stirring of the air intensifies the cold",
    "A touch of wind makes the day cool",
    "It is a temperate day, with a slight breeze",
    "It is very warm, the air stirs slightly",
    "A faint breeze stirs the feverish air"},
   /*
    * wind = 2 
    */
   {
    "A breeze gives the frigid air bite",
    "A breeze swirls the cold air",
    "A lively breeze cools the area",
    "It is a temperate day, with a pleasant breeze",
    "Very warm breezes buffet the area",
    "A breeze ciculates the sweltering air"},
   /*
    * wind = 3 
    */
   {
    "Stiff gusts add cold to the frigid air",
    "The cold air is agitated by gusts of wind",
    "Wind blows in from the north, cooling the area",
    "Gusty winds mix the temperate air",
    "Brief gusts of wind punctuate the warm day",
    "Wind attempts to cut the sweltering heat"},
   /*
    * wind = 4 
    */
   {
    "The frigid air whirls in gusts of wind",
    "A strong, cold wind blows in from the north",
    "Strong wind makes the cool air nip",
    "It is a pleasant day, with gusty winds",
    "Warm, gusty winds move through the area",
    "Blustering winds punctuate the seering heat"},
   /*
    * wind = 5 
    */
   {
    "A frigid gale sets bones shivering",
    "Howling gusts of wind cut the cold air",
    "An angry wind whips the air into a frenzy",
    "Fierce winds tear through the tepid air",
    "Gale-like winds whip up the warm air",
    "Monsoon winds tear the feverish air"}
};

const char *precip_msg[3] = {
   "there is not a cloud in the sky",
   "pristine white clouds are in the sky",
   "thick, grey clouds mask the sun"
};

const char *wind_msg[6] = {
   "there is not a breath of wind in the air",
   "a slight breeze stirs the air",
   "a breeze wafts through the area",
   "brief gusts of wind punctuate the air",
   "angry gusts of wind blow",
   "howling winds whip the air into a frenzy"
};

*****************
* DB.CPP        *
*****************

21. Find:

#if !defined(__CYGWIN__) && defined(SQL)
 #include "sql.h"
#endif

Below that, add:

#include "weather.h"

Then find and remove:

int weath_unit;   /* global weather param */
int rand_factor;
int climate_factor;
int neigh_factor;
int max_vector;

Then find and remove:

void init_area_weather(  );
void load_weatherdata(  );

Then find and remove:

   weath_unit = 10;
   rand_factor = 2;
   climate_factor = 1;
   neigh_factor = 3;
   max_vector = weath_unit * 3;

Then find:

   /*
    * Set time and weather.
    */
   {
      long lhour, lday, lmonth;

      log_string( "Setting time and weather" );

      if( !load_timedata(  ) )   /* Loads time from stored file if true - Samson 1-21-99 */
      {
         boot_log( "%s", "Resetting mud time based on current system time." );
         lhour = ( current_time - 650336715 ) / ( sysdata->pulsetick / sysdata->pulsepersec );
         time_info.hour = lhour % sysdata->hoursperday;
         lday = lhour / sysdata->hoursperday;
         time_info.day = lday % sysdata->dayspermonth;
         lmonth = lday / sysdata->dayspermonth;
         time_info.month = lmonth % sysdata->monthsperyear;
         time_info.year = lmonth / sysdata->monthsperyear;
      }

      if( time_info.hour < sysdata->hoursunrise )
         time_info.sunlight = SUN_DARK;
      else if( time_info.hour < sysdata->hourdaybegin )
         time_info.sunlight = SUN_RISE;
      else if( time_info.hour < sysdata->hoursunset )
         time_info.sunlight = SUN_LIGHT;
      else if( time_info.hour < sysdata->hournightbegin )
         time_info.sunlight = SUN_SET;
      else
         time_info.sunlight = SUN_DARK;
   }

Below that, add:

   if( !load_weathermap(  ) )
   {
      log_string( "Initializing new weather map." );
      InitializeWeatherMap(  );
   }
   else
      log_string( "Weather map data loaded." );

Then find and remove:

   /*
    * Initialize area weather data 
    */
   load_weatherdata(  );
   init_area_weather(  );

*****************
* MAGIC.CPP     *
*****************

22. Find:

#include "smaugaffect.h"

Below that, add:

#include "weather.h"

23. In SPELLF( spell_call_lightning ), Find:

   if( ( !ch->IS_OUTSIDE(  ) || INDOOR_SECTOR( ch->in_room->sector_type ) ) && !ch->has_pcflag( PCFLAG_ONMAP ) && !ch->has_actflag( ACT_ONMAP ) )
   {
      ch->print( "You must be outdoors to cast this spell.\r\n" );
      return rSPELL_FAILED;
   }

ABOVE that, add:

   WeatherCell *cell = getWeatherCell( ch->in_room->area );

Then find:

   if( ch->in_room->area->weather->precip <= 0 )
   {
      ch->print( "You need bad weather.\r\n" );
      return rSPELL_FAILED;
   }

Replace it with:

   if( getPrecip( cell ) < 40 && getEnergy( cell ) < 30 )
   {
      ch->print( "You need bad weather.\r\n" );
      return rSPELL_FAILED;
   }

24. Find:

SPELLF( spell_control_weather )
{
   skill_type *skill = get_skilltype( sn );
   weather_data *weath;
   int change;
   weath = ch->in_room->area->weather;

   change = number_range( -rand_factor, rand_factor ) + ( ch->level * 3 ) / ( 2 * max_vector );

   if( !str_cmp( target_name, "warmer" ) )
      weath->temp_vector += change;
   else if( !str_cmp( target_name, "colder" ) )
      weath->temp_vector -= change;
   else if( !str_cmp( target_name, "wetter" ) )
      weath->precip_vector += change;
   else if( !str_cmp( target_name, "drier" ) )
      weath->precip_vector -= change;
   else if( !str_cmp( target_name, "windier" ) )
      weath->wind_vector += change;
   else if( !str_cmp( target_name, "calmer" ) )
      weath->wind_vector -= change;
   else
   {
      ch->print( "Do you want it to get warmer, colder, wetter, drier, windier, or calmer?\r\n" );
      return rSPELL_FAILED;
   }

   weath->temp_vector = URANGE( -max_vector, weath->temp_vector, max_vector );
   weath->precip_vector = URANGE( -max_vector, weath->precip_vector, max_vector );
   weath->wind_vector = URANGE( -max_vector, weath->wind_vector, max_vector );

   weather_update(  );
   successful_casting( skill, ch, nullptr, nullptr );
   return rNONE;
}

Replace it with:

SPELLF( spell_control_weather )
{
   skill_type *skill = get_skilltype( sn );
   int change;
   WeatherCell *cell = getWeatherCell( ch->in_room->area );

   change = URANGE( 5, number_range( 5, 15 ) + ( ch->level / 10 ), 15 );

   if( !str_cmp( target_name, "warmer" ) )
      IncreaseTemp( cell, change );
   else if( !str_cmp( target_name, "colder" ) )
      DecreaseTemp( cell, change );
   else if( !str_cmp( target_name, "wetter" ) )
      IncreasePrecip( cell, change );
   else if( !str_cmp( target_name, "drier" ) )
      DecreasePrecip( cell, change );
   else if( !str_cmp( target_name, "stormier" ) )
      IncreaseEnergy( cell, change );
   else if( !str_cmp( target_name, "calmer" ) )
      DecreaseEnergy( cell, change );
   else
   {
      ch->print( "Do you want it to get warmer, colder, wetter, " "drier, stormier, or calmer?\r\n" );
      return rSPELL_FAILED;
   }
   successful_casting( skill, ch, NULL, NULL );
   return rNONE;
}

25. in SPELLF( spell_create_water ), find:

   weather_data *weath;
   
Replace it with:

   WeatherCell *cell = getWeatherCell( ch->in_room->area );

Then find:

   weath = ch->in_room->area->weather;

   water = UMIN( level * ( weath->precip >= 0 ? 4 : 2 ), obj->value[0] - obj->value[1] );

Replace it with:

   water = UMIN( level * ( getPrecip( cell ) >= 0 ? 4 : 2 ), obj->value[0] - obj->value[1] );

26. In SPELLF( spell_obj_inv ), find:

            weather_data *weath = ch->in_room->area->weather;

Replace it with:

            WeatherCell *cell = getWeatherCell( ch->in_room->area );

Then find:

            water = UMIN( ( skill->dice ? dice_parse( ch, level, skill->dice ) : level ) * ( weath->precip >= 0 ? 2 : 1 ), obj->value[0] - obj->value[1] );

Replace it with:

            water = UMIN( ( skill->dice ? dice_parse( ch, level, skill->dice ) : level ) * ( getPrecip( cell ) >= 0 ? 2 : 1 ), obj->value[0] - obj->value[1] );

*****************
* MSPECIAL.CPP  *
*****************

27. Find:

#include "roomindex.h"

Below that, add:

#include "weather.h"

In void sayhello( char_data * ch, char_data * t ), find:

            if( IS_CLOUDY( ch->in_room->area->weather ) )
               cmdf( ch, "say Nice %s to go for a walk, %s, I hate it.", buf2, t->name );
            else if( IS_RAINING( ch->in_room->area->weather ) )
               cmdf( ch, "say I hope %s's rain never clears up.. don't you %s?", buf2, t->name );
            else if( IS_SNOWING( ch->in_room->area->weather ) )
               cmdf( ch, "say What a wonderful miserable %s, %s!", buf2, t->name );
            else
               cmdf( ch, "say Such a terrible %s, don't you think?", buf2 );

Replace it with:

            if( getCloudCover( cell ) > 0 )
               cmdf( ch, "say Nice %s to go for a walk, %s, I hate it.", buf2, t->name );
            else if( isRaining( getPrecip( cell ) ) || isRainingSteadily( getPrecip( cell ) ) || isDownpour( getPrecip( cell ) ) || isRaingingHeavily( getPrecip( cell ) ) || isPouring( getPrecip( cell ) ) || isRainingCatsAndDogs( getPrecip( cell ) ) || isTorrentialDownpour( getPrecip( cell ) ) )
            {
               if( getTemp( cell ) <= 32 )
                  cmdf( ch, "say What a wonderful miserable %s, %s!", buf2, t->name );
               else
                  cmdf( ch, "say I hope %s's rain never clears up.. don't you %s?", buf2, t->name );
            }
            else
               cmdf( ch, "say Such a terrible %s, don't you think?", buf2 );

Then find:

            if( IS_CLOUDY( ch->in_room->area->weather ) )
               cmdf( ch, "say Nice %s to go for a walk, %s.", buf2, t->name );
            else if( IS_RAINING( ch->in_room->area->weather ) )
               cmdf( ch, "say I hope %s's rain clears up.. don't you %s?", buf2, t->name );
            else if( IS_SNOWING( ch->in_room->area->weather ) )
               cmdf( ch, "say How can you be out on such a miserable %s, %s!", buf2, t->name );
            else
               cmdf( ch, "say Such a pleasant %s, don't you think?", buf2 );

Replace it with:

            if( getCloudCover( cell ) > 0 )
               cmdf( ch, "say Nice %s to go for a walk, %s.", buf2, t->name );
            else if( isRaining( getPrecip( cell ) ) || isRainingSteadily( getPrecip( cell ) ) || isDownpour( getPrecip( cell ) ) || isRaingingHeavily( getPrecip( cell ) ) || isPouring( getPrecip( cell ) ) || isRainingCatsAndDogs( getPrecip( cell ) ) || isTorrentialDownpour( getPrecip( cell ) ) )
            {
               if( getTemp( cell ) <= 32 )
                  cmdf( ch, "say How can you be out on such a miserable %s, %s!", buf2, t->name );
               else
                  cmdf( ch, "say I hope %s's rain clears up.. don't you %s?", buf2, t->name );
            }
            else
               cmdf( ch, "say Such a pleasant %s, don't you think?", buf2 );

*****************
* OVERLAND.CPP  *
*****************

28. Find:

#include "ships.h"

Below that, add:

#include "weather.h"

29. In void display_map( char_data * ch ), find:

      if( ( ch->in_room->area->weather->precip + 3 * weath_unit - 1 ) / weath_unit > 1 && mod != 1 )
         mod -= 1;

Replace it with:

      if( getCloudCover( cell ) > 0 )
      {
         if( isExtremelyCloudy( getCloudCover( cell ) ) || isModeratelyCloudy( getCloudCover( cell ) ) )
            mod -= 2;
         else if( isPartlyCloudy( getCloudCover( cell ) ) || isCloudy( getCloudCover( cell ) ) )
            mod -= 1;
      }

30. In void map_scan( char_data * ch ), find:

   obj_data *light = ch->get_eq( WEAR_LIGHT );

Below that, add:

   WeatherCell *cell = getWeatherCell( ch->continent->area );

Find:

   if( ( ch->in_room->area->weather->precip + 3 * weath_unit - 1 ) / weath_unit > 1 && mod != 1 )
      mod -= 1;

Replace it with:

   if( getCloudCover( cell ) > 0 )
   {
      if( isExtremelyCloudy( getCloudCover( cell ) ) || isModeratelyCloudy( getCloudCover( cell ) ) )
         mod -= 2;
      else if( isPartlyCloudy( getCloudCover( cell ) ) || isCloudy( getCloudCover( cell ) ) )
         mod -= 1;
   }

*****************
* UPDATE.CPP    *
*****************

31. Find:

#include "variables.h"

Below that, add:

#include "weather.h"

Find and remove the following functions:

void adjust_vectors( weather_data * weather )
void get_weather_echo( weather_data * weath )
void get_time_echo( weather_data * weath )
void weather_update(  )

32. Find function void time_update( void )

Replace it entirely with this:

/*
 * update the time
 */
void time_update( void )
{
   list < descriptor_data * >::iterator ds;
   int n = number_bits( 2 );
   const char *echo = NULL;
   int echo_color = AT_GREY;

   ++time_info.hour;

   if( time_info.hour == 1 )
      update_month_trigger = false;

   if( time_info.hour == sysdata->hourdaybegin || time_info.hour == sysdata->hoursunrise
       || time_info.hour == sysdata->hournoon || time_info.hour == sysdata->hoursunset || time_info.hour == sysdata->hournightbegin )
   {
      for( ds = dlist.begin(  ); ds != dlist.end(  ); ++ds )
      {
         descriptor_data *d = *ds;
         WeatherCell *cell = getWeatherCell( d->character->in_room->area );

         if( d->connected == CON_PLAYING && d->character->IS_OUTSIDE(  ) && !INDOOR_SECTOR( d->character->in_room->sector_type ) && d->character->IS_AWAKE(  ) )
         {
            if( time_info.hour == sysdata->hourdaybegin )
            {
               const char *echo_strings[4] = {
                  "The day has begun.\r\n",
                  "The day has begun.\r\n",
                  "The sky slowly begins to glow.\r\n",
                  "The sun slowly embarks upon a new day.\r\n"
               };
               time_info.sunlight = SUN_RISE;
               echo = echo_strings[n];
               echo_color = AT_YELLOW;
            }

            if( time_info.hour == sysdata->hoursunrise )
            {
               const char *echo_strings[4] = {
                  "The sun rises in the east.\r\n",
                  "The sun rises in the east.\r\n",
                  "The hazy sun rises over the horizon.\r\n",
                  "Day breaks as the sun lifts into the sky.\r\n"
               };
               time_info.sunlight = SUN_LIGHT;
               echo = echo_strings[n];
               echo_color = AT_ORANGE;
            }

            if( time_info.hour == sysdata->hournoon )
            {
               if( getCloudCover( cell ) > 21 )
               {
                  echo = "It's noon.\r\n";
               }
               else
               {
                  const char *echo_strings[2] = {
                     "The intensity of the sun heralds the noon hour.\r\n",
                     "The sun's bright rays beat down upon your shoulders.\r\n"
                  };

                  echo = echo_strings[n % 2];
               }
               time_info.sunlight = SUN_LIGHT;
               echo_color = AT_WHITE;
            }

            if( time_info.hour == sysdata->hoursunset )
            {
               const char *echo_strings[4] = {
                  "The sun slowly disappears in the west.\r\n",
                  "The reddish sun sets past the horizon.\r\n",
                  "The sky turns a reddish orange as the sun ends its journey.\r\n",
                  "The sun's radiance dims as it sinks in the sky.\r\n"
               };
               time_info.sunlight = SUN_SET;
               echo = echo_strings[n];
               echo_color = AT_RED;
            }

            if( time_info.hour == sysdata->hournightbegin )
            {
               if( getCloudCover( cell ) > 21 )
               {
                  const char *echo_strings[2] = {
                     "The night begins.\r\n",
                     "Twilight descends around you.\r\n"
                  };

                  echo = echo_strings[n % 2];
               }
               else
               {
                  const char *echo_strings[2] = {
                     "The moon's gentle glow diffuses through the night sky.\r\n",
                     "The night sky gleams with glittering starlight.\r\n"
                  };

                  echo = echo_strings[n % 2];
               }
               time_info.sunlight = SUN_DARK;
               echo_color = AT_DBLUE;
            }

            if( !echo )
               continue;

            d->character->set_color( echo_color );
            d->character->print( echo );
         }
      }
   }

   if( time_info.hour == sysdata->hourmidnight )
   {
      time_info.hour = 0;
      ++time_info.day;
      /*
       * Sweep old crap from auction houses on daily basis - Samson 11-1-99 
       */
      clean_auctions(  );
   }

   if( time_info.day >= sysdata->dayspermonth )
   {
      time_info.day = 0;
      ++time_info.month;
      update_month_trigger = true;
   }

   if( time_info.month >= sysdata->monthsperyear )
   {
      time_info.month = 0;
      ++time_info.year;
   }
   calc_season(  );  /* Samson 5-6-99 */
   /*
    * Save game world time - Samson 1-21-99 
    */
   save_timedata(  );
}

33. In void update_handler( void ), find:

   // Time. Does not pass when no players are on.
   if( sysdata->playersonline > 0 )
   {
      if( --pulse_time <= 0 )
      {
         pulse_time = sysdata->pulsecalendar;

         time_update(  );
         weather_update(  );
         char_calendar_update(  );
      }
   }
   
Replace it with:

   // Time and weather. Does not pass when no players are on.
   if( sysdata->playersonline > 0 )
   {
      if( --pulse_time <= 0 )
      {
         pulse_time = sysdata->pulsecalendar;

         time_update(  );
         char_calendar_update(  );
         UpdateWeather(  ); /* New Weather Updater -Kayle */
      }
   }

*****************
* MUD.H         *
*****************

34. In mud.h, find and remove the following:

#define GET_TEMP_UNIT(weather)   ((weather->temp + 3*weath_unit - 1)/weath_unit)
#define GET_PRECIP_UNIT(weather) ((weather->precip + 3*weath_unit - 1)/weath_unit)
#define GET_WIND_UNIT(weather)   ((weather->wind + 3*weath_unit - 1)/weath_unit)

#define IS_RAINING(weather)      (GET_PRECIP_UNIT(weather)>PRECIP_NORMAL)
#define IS_WINDY(weather)        (GET_WIND_UNIT(weather)>WIND_NORMAL)
#define IS_CLOUDY(weather)       (GET_PRECIP_UNIT(weather)>1)
#define IS_TCOLD(weather)        (GET_TEMP_UNIT(weather)==TEMP_COLD)
#define IS_COOL(weather)         (GET_TEMP_UNIT(weather)==TEMP_COOL)
#define IS_HOT(weather)          (GET_TEMP_UNIT(weather)==TEMP_HOT)
#define IS_WARM(weather)         (GET_TEMP_UNIT(weather)==TEMP_WARM)
#define IS_SNOWING(weather)      (IS_RAINING(weather) && IS_COOL(weather))

*****************
* MAKEFILE      *
*****************

35. Add weather.cpp to your list of C_FILES.

36. Make clean, compile.

37. Address any issues the compiler brings up. Some of the removed material may be something
you made use of in something that isn't in the base AFKMud distribution. These issues will
need to be taken care of before you can coninue.

38. Remove the weather.dat file from the system folder. It will no longer be used.

39. Boot the game.

If there are any problems with this installation, feel free to post your
question to the forums at https://smaugmuds.afkmods.com.

This code has been installed and tested on AFKMud 2.5.0, which is an advanced C++
derivative of the Smaug 1.8b and SmaugFUSS code.

The Smaug FUSS Project is maintained on servers which run the Ubuntu family of linux servers.

Limited testing has also been done on the Cygwin package under Windows 10.

Users of BSD, MSVC, MSVC++, or Macintosh platforms are on their own as The
Smaug FUSS Project does not have access to these development environments for testing.
The Smaug FUSS Project can be found at: https://smaugmuds.afkmods.com

No guarantees are made that this code will be compatible with your codebase and any
modifications you may have made to it. No warranty of any kind is expressed or implied
by the use of this code, and I am not responsible for any damages which may result
from the application of this snippet to your codebase. I cannot guarantee compatibility
any codebase outside of AFKMud.

Samson
Former Owner and Implementor of Alsherok
