diff options
Diffstat (limited to 'src/game/Weather.cpp')
-rw-r--r-- | src/game/Weather.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/game/Weather.cpp b/src/game/Weather.cpp new file mode 100644 index 00000000000..77e81f0b16d --- /dev/null +++ b/src/game/Weather.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup world +*/ + +#include "Weather.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "Player.h" +#include "World.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Util.h" + +/// 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; + + sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (1000*MINUTE)) ); +} + +/// Launch a weather update +bool Weather::Update(time_t diff) +{ + if (m_timer.GetCurrent()>=0) + m_timer.Update(diff); + else m_timer.SetCurrent(0); + + ///- If the timer has passed, ReGenerate the weather + if(m_timer.Passed()) + { + m_timer.Reset(); + // update only if Regenerate has changed the weather + if(ReGenerate()) + { + ///- Weather will be removed if not updated (no players in zone anymore) + if(!UpdateWeather()) + return false; + } + } + return true; +} + +/// Calculate the new weather +bool Weather::ReGenerate() +{ + if (!m_weatherChances) + { + m_type = WEATHER_TYPE_FINE; + m_grade = 0.0f; + return false; + } + + /// 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); + + if (u < 30) + return false; + + // remember old values + WeatherType old_type = m_type; + float old_grade = m_grade; + + //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 + time_t gtime = sWorld.GetGameTime(); + struct tm * ltime = localtime(>ime); + uint32 season = ((ltime->tm_yday - 78 + 365)/91)%4; + + static char const* seasonName[WEATHER_SEASONS] = { "spring", "summer", "fall", "winter" }; + + sLog.outDebug("Generating a change in %s weather for zone %u.", seasonName[season], m_zone); + + if ((u < 60) && (m_grade < 0.33333334f)) // Get fair + { + m_type = WEATHER_TYPE_FINE; + m_grade = 0.0f; + } + + if ((u < 60) && (m_type != WEATHER_TYPE_FINE)) // Get better + { + m_grade -= 0.33333334f; + return true; + } + + if ((u < 90) && (m_type != WEATHER_TYPE_FINE)) // Get worse + { + m_grade += 0.33333334f; + return true; + } + + if (m_type != WEATHER_TYPE_FINE) + { + /// Radical change: + ///- if light -> heavy + ///- if medium -> change weather type + ///- if heavy -> 50% light, 50% change weather type + + 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; + } + } + + // 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; + + uint32 rnd = urand(0, 99); + if(rnd <= chance1) + m_type = WEATHER_TYPE_RAIN; + else if(rnd <= chance2) + m_type = WEATHER_TYPE_SNOW; + else if(rnd <= chance3) + m_type = WEATHER_TYPE_STORM; + else + m_type = WEATHER_TYPE_FINE; + + /// New weather statistics (if not fine): + ///- 85% light + ///- 7% medium + ///- 7% heavy + /// If fine 100% sun (no fog) + + 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; + } + + // return true only in case weather changes + return m_type != old_type || m_grade != old_grade; +} + +void Weather::SendWeatherUpdateToPlayer(Player *player) +{ + WorldPacket data( SMSG_WEATHER, (4+4+4) ); + + data << uint32(GetWeatherState()) << (float)m_grade << uint8(0); + player->GetSession()->SendPacket( &data ); +} + +void Weather::SendFineWeatherUpdateToPlayer(Player *player) +{ + WorldPacket data( SMSG_WEATHER, (4+4+4) ); + + data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0); + player->GetSession()->SendPacket( &data ); +} + +/// Send the new weather to all players in the zone +bool Weather::UpdateWeather() +{ + Player* player = sWorld.FindPlayerInZone(m_zone); + if(!player) + return false; + + ///- 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; + + WeatherState state = GetWeatherState(); + + WorldPacket data( SMSG_WEATHER, (4+4+4) ); + data << uint32(state) << (float)m_grade << uint8(0); + player->SendMessageToSet( &data, true ); + + ///- 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); + + return true; +} + +/// Set the weather +void Weather::SetWeather(WeatherType type, float grade) +{ + if(m_type == type && m_grade == grade) + return; + + m_type = type; + m_grade = grade; + UpdateWeather(); +} + +/// Get the sound number associated with the current weather +WeatherState Weather::GetWeatherState() const +{ + if (m_grade<0.27f) + return WEATHER_STATE_FINE; + + switch(m_type) + { + case WEATHER_TYPE_RAIN: + if(m_grade<0.40f) + return WEATHER_STATE_LIGHT_RAIN; + else if(m_grade<0.70f) + return WEATHER_STATE_MEDIUM_RAIN; + else + return WEATHER_STATE_HEAVY_RAIN; + case WEATHER_TYPE_SNOW: + if(m_grade<0.40f) + return WEATHER_STATE_LIGHT_SNOW; + else if(m_grade<0.70f) + return WEATHER_STATE_MEDIUM_SNOW; + else + return WEATHER_STATE_HEAVY_SNOW; + case WEATHER_TYPE_STORM: + if(m_grade<0.40f) + return WEATHER_STATE_LIGHT_SANDSTORM; + else if(m_grade<0.70f) + 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; + } +} |