cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "kernel.h"
#include "sendsys.h"
#include "climate.h"
#include "pflags.h"
#include "sflags.h"
#include "lflags.h"
#include "bprintf.h"
#include "parse.h" 
#include "rooms.h"
#include "xrweathermsgs.h"
#include "log.h"

#ifdef XR_WEATHER

Boolean is_daytime( int location )
  {
  time_t t_time;
  struct tm *the_time;

  time (&t_time);
  the_time = localtime (&t_time);

  if( 5 < the_time->tm_hour && the_time->tm_hour < 17 )
    return True;

  return False;
  
}

/*
 * Function used to display weather to mynum when entering a room.
 */

void show_weather (void)
  {
  int temp;
  int wind;
  int rain;

  if( !ltstflg( ploc (mynum), LFL_OUTDOORS ) )
    return;

  /* Determine the wind array position. */
  wind = wind2num( global_weather->windspeed );

  /* Determine the Rain array position. */
  rain = rain2num( mynum, global_weather->rain );
 
  /* Determine the Location/temp array position. */
  temp = get_temp( ploc(mynum) );
  if( temp < 40 )
    temp = 1; /* Snowing land & water */
  else if( ltstflg( ploc(mynum), LFL_ON_WATER ) ) 
    temp = 2; /* On Water */
  else
    temp = 0; /* On Land */

  /* Adjust for only wind messages (not raining. :)) */
  if( rain == 0 )
    temp = 0;

  /* Print the message */

  if( global_weather->sunny ) {
    if( is_daytime( ploc(mynum) ) )
      bprintf( "The &+Ysun&N is shining.\n" );
    else
      bprintf( "The &+Ymoonlight&N shines down from above.\n" );
  }

  bprintf( "%s", xrweathermsgs[wind][rain][temp] );
  return;
 
}

/*
 * Game command to tell us what the weather is like.  
 */

void weathercom (void)
  {
  int room;

  if (!ptstflg (mynum, PFL_WEATHER)) {
    erreval ();
    return;
  }

  if( ( room = getroomnum( ) ) == 0 )
    room = ploc( mynum );

  if( plev(mynum) >= LVL_SHALAFI ) {
    if( !strcmp( wordbuf, "sunny" ) ) {
      start_weather( WEATHER_SUNNY );
      return;
    }
    else if( !strcmp(wordbuf, "cloudy") ) {
      start_weather( WEATHER_CLOUDY );
      return;
    }
    else if( !strcmp(wordbuf, "rainy" ) ) {
      if( global_weather->sunny )
        start_weather( WEATHER_CLOUDY );
      else
        start_weather( WEATHER_RAIN );
      return;
    }
  }

  bprintf( "&+CCurrent weather conditions for &+B%s&+C:\n", 
           sdesc( room ) );
  bprintf( "&+GTemperature: &+W%d degrees.\n", get_temp( room ) );
  bprintf( "&+GLatitude:    &+W%d degrees.\n", zlatitude( lzone( room ) ) );
  bprintf( "&+GAltitude:    &+W%d feet.\n", laltitude( room ) );
  bprintf( "&+GRainfall:    &+W%d mm per year.\n", zrainfall( lzone( room ) ) );

  bprintf( "\n&+CGlobal weather conditions:\n" );
  bprintf( "&+GWeather           : " );
    if( !global_weather->sunny )
        bprintf( "&+LCloudy\n" );
    else if( is_daytime(room) )
      bprintf( "&+YSunny\n" );
    else
      bprintf( "&+WMoonlit\n" );
  bprintf( "&+GWind Speed        : &+W%d\n", global_weather->windspeed );
  if( plev(mynum) >= LVL_SHALAFI )
    {
    bprintf( "&+GRain              : &+W%d\n", global_weather->rain );
    bprintf( "&+GWeather Timer     : &+W%d\n", global_weather->timer );
    if( global_weather->sunny == False ) {
      bprintf( "&+GEnd of Standby    : &+W%d\n", global_weather->standby );
      bprintf( "&+GEnd of Decline    : &+W%d\n", global_weather->decline );
      bprintf( "&+GEnd of Steady     : &+W%d\n", global_weather->steady );
    }
    bprintf( "&+GWeather Until     : &+W%d\n", global_weather->weatherlen );
    if( global_weather->sunny == False )
      bprintf( "&+GBottom            : &+W%d\n", global_weather->bottom );
  }
  return;
  
}

/*
 * NASTY function to get the temperature in a given room.  It's based on:
 *
 * 1) Time Of The Year
 * 2) Latitude
 * 3) Altitude
 * 4) Rainfall 
 * 5) Wind Speed
 *
 * Don't even try to comprehend it.  :)
 */

int get_temp( int location )
  {
  int temperature;
  time_t t_time;
  struct tm *the_time;

  time (&t_time);
  the_time = localtime (&t_time);

  temperature = 125+global_weather->sunny*10-
    pow(zlatitude(lzone(location)),2)/75-
    laltitude(location)/250-
    abs((the_time->tm_mon-6))*7*zlatitude(lzone(location))/90-
    abs(global_weather->windspeed)/4-
    (int)((double)10*log10((double)(1+zrainfall(lzone(location)))) *
          (double)((double)1-((double)zlatitude(lzone(location))/(double)90)))-
    (int)((double).6 * 
          ((double)7 -log10((double)(1+zrainfall(lzone(location)))))*
          abs((the_time->tm_hour-12))* 
          (double)(110-zlatitude(lzone(location)))/(double)90);

  return temperature; 
}

/*
 * Change the wind speed once every two minutes by +/- 16 usually 
 * much smaller values than that, though.  :)
 */

void update_weather( )
  {
  int variance, oldwind;

  /* Check to run weather routines every two minutes */
  global_weather->counter += 1;
  if ( global_weather->counter != 60 ) 
     return;

  global_weather->counter = 0;
  global_weather->timer += 1;

  /* Wind variance stuff */
  oldwind = global_weather->windspeed;

  variance = (((rand()%2)?1:-1)* 
             (rnd(8)*rnd(8)*rnd(8)*rnd(8)/256));
  if ( variance > 0 && global_weather->windspeed >= 25 &&
       global_weather->windspeed < 80 && ( rnd(20) == 1 ) )
     variance = -variance;
  if(((global_weather->timer - global_weather->last_hurricane ) < 120 ) &&  
          variance > 0 && global_weather->windspeed > 75 )
     variance = -variance;
  global_weather->windspeed += variance;
  if( global_weather->windspeed <= -10 ) 
    global_weather->windspeed = -10;
  else if( global_weather->windspeed >= 100 ) {
    start_weather( WEATHER_HURRICANE );
  }
  windmsgs( oldwind );

  /*
   * Rain stuff.  Check to see if it's time to switch from rainy<->sunny 
   */
  if( (global_weather->weatherlen - global_weather->timer) <= 0 )
    {
    if( global_weather->sunny )
      start_weather( WEATHER_CLOUDY );
    else
      start_weather( WEATHER_SUNNY );
  }

  /* 
   * Dont' update rain info if it's:
   *
   * a) sunny
   * b) waiting to start to decline to steady
   * c) at steady
   */
  if( global_weather->sunny || 
    (global_weather->timer < global_weather->standby )||
    (global_weather->decline < global_weather->timer &&
     global_weather->timer < global_weather->steady)) 
    return;

  /* Time to start a new cycle? */
  if( global_weather->timer > global_weather->duration ) {
    start_weather( WEATHER_RAIN );
    return;
  }

  /* We're declining. */
  if(global_weather->standby < global_weather->timer < global_weather->decline)
    {
    int old_value = global_weather->rain;
    global_weather->rain = 10000 - (int)((double)(10000 - global_weather->bottom) *
                           (double)(global_weather->timer - global_weather->standby) /
                           (double)(global_weather->decline - global_weather->standby));            
    rainmsgs( old_value );
    return;
  } 

  /* Inclining */
  if(global_weather->duration > global_weather->timer > global_weather->steady)
    {
    int old_value = global_weather->rain;
    global_weather->rain = (int)( (double)(global_weather->timer - global_weather->steady) * 
                           (double)(10000 - global_weather->bottom ) / 
                           (double)(global_weather->duration - global_weather->steady) + 
                           (double)global_weather->bottom);
    rainmsgs( old_value );
    return;
  }

  if( global_weather->timer >= global_weather->duration )
    {
    if((global_weather->weatherlen - global_weather->timer) > 5)
      start_weather( WEATHER_RAIN );
    return;
  }
  return;
}

/*
 * Routine to boot weather sequences.
 */

void boot_weather( )
  {
  FILE *weatherfile;

  global_weather->windspeed = 0;
  global_weather->timer = 0;
  global_weather->counter = 0;
  global_weather->last_hurricane = 0;
  global_weather->bottom = 0;
  global_weather->duration = 0;
  global_weather->decline = 0;
  global_weather->steady = 0;

  if( ( weatherfile = FOPEN( WEATHER_FILE, "r" )) == NULL ) {
    start_weather( WEATHER_SUNNY );
    return;
  }

  fscanf( weatherfile, "Sunny:      %d\n", (int *) &global_weather->sunny );
  fscanf( weatherfile, "Windspeed:  %d\n", &global_weather->windspeed );
  fscanf( weatherfile, "Rain:       %d\n", &global_weather->rain );
  fscanf( weatherfile, "Timer:      %d\n", &global_weather->timer );
  fscanf( weatherfile, "Counter:    %d\n", &global_weather->counter );
  fscanf( weatherfile, "LHurricane: %d\n", &global_weather->last_hurricane );
  fscanf( weatherfile, "WeatherLen: %d\n", &global_weather->weatherlen );
  fscanf( weatherfile, "Bottom:     %d\n", &global_weather->bottom );
  fscanf( weatherfile, "Duration:   %d\n", &global_weather->duration );
  fscanf( weatherfile, "Standby:    %d\n", &global_weather->standby );
  fscanf( weatherfile, "Decline:    %d\n", &global_weather->decline );
  fscanf( weatherfile, "Steady:     %d\n", &global_weather->steady );

  FCLOSE( weatherfile );

}

void start_weather( int weather )
  {
  int steady;

  if( weather == WEATHER_SUNNY ) {
    global_weather->weatherlen = (int)((double)(rnd(2)*rnd(2)*rnd(2)*rnd(2)*
				 rnd(2)*rnd(2)*rnd(2)*rnd(2)*rnd(2)*rnd(2)*
				 rnd(2)*rnd(2)*rnd(2)*rnd(2))*((double).67+
                                 drand48()*(double)2/(double)3)/(double)2);
    global_weather->weatherlen += global_weather->timer;
    global_weather->sunny = True;
    global_weather->rain = 10000;
    return;
  }
  if( weather == WEATHER_CLOUDY ) {
    global_weather->sunny = False;
    global_weather->weatherlen = (int)((double)(rnd(4)*rnd(4)*rnd(4)*rnd(4)*
                                 rnd(4)*rnd(4)*rnd(4))*((double).8+drand48()*
				 (double)2/(double)5)/(double)2);
    global_weather->weatherlen += global_weather->timer;
    start_weather( WEATHER_RAIN );
    return;
  } 
  if( weather == WEATHER_RAIN ) {
    int raintime;

    /* Duration of rainy spell */
    global_weather->duration = 3+(int)(drand48()*
                                      (double)global_weather->weatherlen); 

    /* Time before it starts to decline. */
    global_weather->standby = 1+(int)((double)global_weather->duration*
                      drand48()/(double)2);
    if( global_weather->duration - global_weather->standby == 1 )
      global_weather->standby = 1;

    /* Length of the actual rain period */
    raintime = global_weather->duration - global_weather->standby;

    /* The time that it takes to go from 10000 to bottom */
    if( raintime == 2 )
      global_weather->decline = 1;
    else
      global_weather->decline = rnd((raintime/2));
    
    /* Time that the rain will stay at bottom */
    
    steady = raintime - global_weather->decline - 1;
    global_weather->steady = rnd(steady);

    /* The hardest that it will rain during this spell */
    if( global_weather->duration > 15 )
      global_weather->bottom = rnd(10)*rnd(10)*rnd(100);
    else
      global_weather->bottom = 10000-rnd(8500);

    /* 
     * Now the tricky part.  Convert all of these values to "ticks" WHEN
     * they will happen instead of times. :)  Also these times are when
     * the periods end instead of begin.
     */
    global_weather->standby += global_weather->timer;
    global_weather->decline += global_weather->standby;
    global_weather->steady += global_weather->decline;
    global_weather->duration += global_weather->timer;
    return;
  }
  if( weather == WEATHER_HURRICANE ) {
    /* Not implemented yet */
    mudlog( "Hurricane Started!!!" );
    global_weather->last_hurricane = global_weather->timer;
    global_weather->windspeed  = 100;
    return;
  }
  mudlog( "Unknown weather in start_weather %d!", weather );
  return;
}

/*
 * Sends a message to everyone if the weather changes in their room 
 */

void rainmsgs( int oldvalue ) {
  if( oldvalue == global_weather->rain )
    return;
  send_g_msg( DEST_ALL, raintest_func, oldvalue, NULL );
  return;
}

void windmsgs( int oldwind ) {
  if( wind2num( oldwind ) == wind2num( global_weather->windspeed ) )
    return;
  send_g_msg( DEST_ALL, windtest_func, oldwind, NULL );
  return;
}

char *windtest_func( int plr, int arg, char *msg ) {
  if( !ltstflg( ploc( plr ), LFL_OUTDOORS ) || ststflg( plr, SFL_NOWET ) ||
      ststflg( plr, SFL_QUIET ) )
    return NULL;

  return xrweatherwindmsgs[wind2num(arg)][wind2num(global_weather->windspeed)];
}

char * raintest_func( int plr, int arg, char *msg ) {
  if( !ltstflg( ploc( plr ), LFL_OUTDOORS ) || ststflg( plr, SFL_NOWET ) ||
      ststflg( plr, SFL_QUIET ) )
    return NULL;

  return xrweatherstartmsgs[rain2num( plr, arg )][rain2num( plr, global_weather->rain )][((get_temp(ploc(plr)) < 40) ? 1 : 0)];    
}

/* 
 * Function to convert actual rainfall values into a value used to access an 
 * array.  Returns a value from 0-7 depending on the rainfall of plr.
 */

int rain2num( int plr, int value ) {
  if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 2500 )
    return 7;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 1000 )
    return 6;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 500 )
    return 5;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 300 )
    return 4;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 120 )
    return 3;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 30 )
    return 2;
  else if( ( zrainfall( lzone(ploc(plr) ) ) - value ) > 0 )
    return 1;
  else
    return 0;
}

int wind2num( int value ) {
  if( abs( value ) > 84 )
    return 6;
  else if( abs( value ) > 59 )
    return 5;
  else if( abs( value ) > 39 )
    return 4;
  else if( abs( value ) > 24 )
    return 3;
  else if( abs( value ) > 10 )
    return 2;
  else if( abs( value ) > 0 )
    return 1;
  else
    return 0;
}
#endif /* XR_WEATHER */