2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* 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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* 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, write to the Free Software
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/** \file
\ingroup world
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Weather.h"
#include "WorldPacket.h"
#include "Player.h"
#include "World.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "Util.h"
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Create the Weather object
Weather :: Weather ( uint32 zone , WeatherZoneChances const * weatherChances ) : m_zone ( zone ), m_weatherChances ( weatherChances )
{
m_timer . SetInterval ( sWorld . getConfig ( CONFIG_INTERVAL_CHANGEWEATHER ));
m_type = WEATHER_TYPE_FINE ;
m_grade = 0 ;
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
sLog . outDetail ( "WORLD: Starting weather system for zone %u (change every %u minutes)." , m_zone , ( uint32 )( m_timer . GetInterval () / ( MINUTE * IN_MILISECONDS )));
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Launch a weather update
2009-01-21 16:18:57 -06:00
bool Weather :: Update ( uint32 diff )
2008-10-02 16:23:55 -05:00
{
2010-04-07 23:56:35 +02:00
if ( m_timer . GetCurrent () >= 0 )
2008-10-02 16:23:55 -05:00
m_timer . Update ( diff );
else m_timer . SetCurrent ( 0 );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- If the timer has passed, ReGenerate the weather
2010-04-07 19:14:10 +02:00
if ( m_timer . Passed ())
2008-10-02 16:23:55 -05:00
{
m_timer . Reset ();
// update only if Regenerate has changed the weather
2010-04-07 19:14:10 +02:00
if ( ReGenerate ())
2008-10-02 16:23:55 -05:00
{
///- Weather will be removed if not updated (no players in zone anymore)
2010-04-07 19:14:10 +02:00
if ( ! UpdateWeather ())
2008-10-02 16:23:55 -05:00
return false ;
}
}
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Calculate the new weather
bool Weather :: ReGenerate ()
{
if ( ! m_weatherChances )
{
m_type = WEATHER_TYPE_FINE ;
m_grade = 0.0f ;
return false ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Weather statistics:
///- 30% - no change
///- 30% - weather gets better (if not fine) or change weather type
///- 30% - weather worsens (if not fine)
///- 10% - radical change (if not fine)
uint32 u = urand ( 0 , 99 );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( u < 30 )
return false ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// remember old values
WeatherType old_type = m_type ;
float old_grade = m_grade ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
//78 days between January 1st and March 20nd; 365/4=91 days by season
// season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html
2009-12-24 10:20:15 +01:00
time_t gtime = sWorld . GetGameTime ();
2008-10-02 16:23:55 -05:00
struct tm * ltime = localtime ( & gtime );
uint32 season = (( ltime -> tm_yday - 78 + 365 ) / 91 ) % 4 ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
static char const * seasonName [ WEATHER_SEASONS ] = { "spring" , "summer" , "fall" , "winter" };
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
sLog . outDebug ( "Generating a change in %s weather for zone %u." , seasonName [ season ], m_zone );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if (( u < 60 ) && ( m_grade < 0.33333334f )) // Get fair
{
m_type = WEATHER_TYPE_FINE ;
m_grade = 0.0f ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if (( u < 60 ) && ( m_type != WEATHER_TYPE_FINE )) // Get better
{
m_grade -= 0.33333334f ;
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if (( u < 90 ) && ( m_type != WEATHER_TYPE_FINE )) // Get worse
{
m_grade += 0.33333334f ;
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( m_type != WEATHER_TYPE_FINE )
{
/// Radical change:
///- if light -> heavy
///- if medium -> change weather type
///- if heavy -> 50% light, 50% change weather type
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( m_grade < 0.33333334f )
{
m_grade = 0.9999f ; // go nuts
return true ;
}
else
{
if ( m_grade > 0.6666667f )
{
// Severe change, but how severe?
uint32 rnd = urand ( 0 , 99 );
if ( rnd < 50 )
{
m_grade -= 0.6666667f ;
return true ;
}
}
m_type = WEATHER_TYPE_FINE ; // clear up
m_grade = 0 ;
}
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// At this point, only weather that isn't doing anything remains but that have weather data
uint32 chance1 = m_weatherChances -> data [ season ]. rainChance ;
uint32 chance2 = chance1 + m_weatherChances -> data [ season ]. snowChance ;
uint32 chance3 = chance2 + m_weatherChances -> data [ season ]. stormChance ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 rnd = urand ( 0 , 99 );
2010-04-07 19:14:10 +02:00
if ( rnd <= chance1 )
2008-10-02 16:23:55 -05:00
m_type = WEATHER_TYPE_RAIN ;
2010-04-07 19:14:10 +02:00
else if ( rnd <= chance2 )
2008-10-02 16:23:55 -05:00
m_type = WEATHER_TYPE_SNOW ;
2010-04-07 19:14:10 +02:00
else if ( rnd <= chance3 )
2008-10-02 16:23:55 -05:00
m_type = WEATHER_TYPE_STORM ;
else
m_type = WEATHER_TYPE_FINE ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// New weather statistics (if not fine):
///- 85% light
///- 7% medium
///- 7% heavy
/// If fine 100% sun (no fog)
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( m_type == WEATHER_TYPE_FINE )
{
m_grade = 0.0f ;
}
else if ( u < 90 )
{
m_grade = rand_norm () * 0.3333f ;
}
else
{
// Severe change, but how severe?
rnd = urand ( 0 , 99 );
if ( rnd < 50 )
m_grade = rand_norm () * 0.3333f + 0.3334f ;
else
m_grade = rand_norm () * 0.3333f + 0.6667f ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// return true only in case weather changes
return m_type != old_type || m_grade != old_grade ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void Weather :: SendWeatherUpdateToPlayer ( Player * player )
{
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_WEATHER , ( 4 + 4 + 4 ));
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
data << uint32 ( GetWeatherState ()) << ( float ) m_grade << uint8 ( 0 );
2010-04-07 22:59:46 +02:00
player -> GetSession () -> SendPacket ( & data );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void Weather :: SendFineWeatherUpdateToPlayer ( Player * player )
{
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_WEATHER , ( 4 + 4 + 4 ));
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
data << ( uint32 ) WEATHER_STATE_FINE << ( float ) 0.0f << uint8 ( 0 );
2010-04-07 22:59:46 +02:00
player -> GetSession () -> SendPacket ( & data );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Send the new weather to all players in the zone
bool Weather :: UpdateWeather ()
{
Player * player = sWorld . FindPlayerInZone ( m_zone );
2010-04-07 19:14:10 +02:00
if ( ! player )
2008-10-02 16:23:55 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Send the weather packet to all players in this zone
if ( m_grade >= 1 )
m_grade = 0.9999f ;
else if ( m_grade < 0 )
m_grade = 0.0001f ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
WeatherState state = GetWeatherState ();
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_WEATHER , ( 4 + 4 + 4 ));
2008-10-02 16:23:55 -05:00
data << uint32 ( state ) << ( float ) m_grade << uint8 ( 0 );
2010-04-07 22:59:46 +02:00
player -> SendMessageToSet ( & data , true );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Log the event
char const * wthstr ;
switch ( state )
{
case WEATHER_STATE_LIGHT_RAIN :
wthstr = "light rain" ;
break ;
case WEATHER_STATE_MEDIUM_RAIN :
wthstr = "medium rain" ;
break ;
case WEATHER_STATE_HEAVY_RAIN :
wthstr = "heavy rain" ;
break ;
case WEATHER_STATE_LIGHT_SNOW :
wthstr = "light snow" ;
break ;
case WEATHER_STATE_MEDIUM_SNOW :
wthstr = "medium snow" ;
break ;
case WEATHER_STATE_HEAVY_SNOW :
wthstr = "heavy snow" ;
break ;
case WEATHER_STATE_LIGHT_SANDSTORM :
wthstr = "light sandstorm" ;
break ;
case WEATHER_STATE_MEDIUM_SANDSTORM :
wthstr = "medium sandstorm" ;
break ;
case WEATHER_STATE_HEAVY_SANDSTORM :
wthstr = "heavy sandstorm" ;
break ;
case WEATHER_STATE_THUNDERS :
wthstr = "thunders" ;
break ;
case WEATHER_STATE_BLACKRAIN :
wthstr = "blackrain" ;
break ;
case WEATHER_STATE_FINE :
default :
wthstr = "fine" ;
break ;
}
sLog . outDetail ( "Change the weather of zone %u to %s." , m_zone , wthstr );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Set the weather
void Weather :: SetWeather ( WeatherType type , float grade )
{
2010-04-07 19:14:10 +02:00
if ( m_type == type && m_grade == grade )
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
m_type = type ;
m_grade = grade ;
UpdateWeather ();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Get the sound number associated with the current weather
WeatherState Weather :: GetWeatherState () const
{
if ( m_grade < 0.27f )
return WEATHER_STATE_FINE ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
switch ( m_type )
{
case WEATHER_TYPE_RAIN :
2010-04-07 19:14:10 +02:00
if ( m_grade < 0.40f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_LIGHT_RAIN ;
2010-04-07 19:14:10 +02:00
else if ( m_grade < 0.70f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_MEDIUM_RAIN ;
else
return WEATHER_STATE_HEAVY_RAIN ;
case WEATHER_TYPE_SNOW :
2010-04-07 19:14:10 +02:00
if ( m_grade < 0.40f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_LIGHT_SNOW ;
2010-04-07 19:14:10 +02:00
else if ( m_grade < 0.70f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_MEDIUM_SNOW ;
else
return WEATHER_STATE_HEAVY_SNOW ;
case WEATHER_TYPE_STORM :
2010-04-07 19:14:10 +02:00
if ( m_grade < 0.40f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_LIGHT_SANDSTORM ;
2010-04-07 19:14:10 +02:00
else if ( m_grade < 0.70f )
2008-10-02 16:23:55 -05:00
return WEATHER_STATE_MEDIUM_SANDSTORM ;
else
return WEATHER_STATE_HEAVY_SANDSTORM ;
case WEATHER_TYPE_BLACKRAIN :
return WEATHER_STATE_BLACKRAIN ;
case WEATHER_TYPE_THUNDERS :
return WEATHER_STATE_THUNDERS ;
case WEATHER_TYPE_FINE :
default :
return WEATHER_STATE_FINE ;
}
}
2009-02-17 20:07:49 -06:00