* Fix some warlock talent work
[getmangos.git] / src / game / Weather.cpp
blob0a4fe9edb8fac90dd81b85f7677b58b956b71887
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 /** \file
20 \ingroup world
23 #include "Weather.h"
24 #include "WorldPacket.h"
25 #include "WorldSession.h"
26 #include "Player.h"
27 #include "World.h"
28 #include "Log.h"
29 #include "ObjectMgr.h"
30 #include "Util.h"
32 /// Create the Weather object
33 Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone(zone), m_weatherChances(weatherChances)
35 m_timer.SetInterval(sWorld.getConfig(CONFIG_INTERVAL_CHANGEWEATHER));
36 m_type = WEATHER_TYPE_FINE;
37 m_grade = 0;
39 sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (1000*MINUTE)) );
42 /// Launch a weather update
43 bool Weather::Update(time_t diff)
45 if (m_timer.GetCurrent()>=0)
46 m_timer.Update(diff);
47 else m_timer.SetCurrent(0);
49 ///- If the timer has passed, ReGenerate the weather
50 if(m_timer.Passed())
52 m_timer.Reset();
53 // update only if Regenerate has changed the weather
54 if(ReGenerate())
56 ///- Weather will be removed if not updated (no players in zone anymore)
57 if(!UpdateWeather())
58 return false;
61 return true;
64 /// Calculate the new weather
65 bool Weather::ReGenerate()
67 if (!m_weatherChances)
69 m_type = WEATHER_TYPE_FINE;
70 m_grade = 0.0f;
71 return false;
74 /// Weather statistics:
75 ///- 30% - no change
76 ///- 30% - weather gets better (if not fine) or change weather type
77 ///- 30% - weather worsens (if not fine)
78 ///- 10% - radical change (if not fine)
79 uint32 u = urand(0, 99);
81 if (u < 30)
82 return false;
84 // remember old values
85 WeatherType old_type = m_type;
86 float old_grade = m_grade;
88 //78 days between January 1st and March 20nd; 365/4=91 days by season
89 // season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html
90 time_t gtime = sWorld.GetGameTime();
91 struct tm * ltime = localtime(&gtime);
92 uint32 season = ((ltime->tm_yday - 78 + 365)/91)%4;
94 static char const* seasonName[WEATHER_SEASONS] = { "spring", "summer", "fall", "winter" };
96 sLog.outDebug("Generating a change in %s weather for zone %u.", seasonName[season], m_zone);
98 if ((u < 60) && (m_grade < 0.33333334f)) // Get fair
100 m_type = WEATHER_TYPE_FINE;
101 m_grade = 0.0f;
104 if ((u < 60) && (m_type != WEATHER_TYPE_FINE)) // Get better
106 m_grade -= 0.33333334f;
107 return true;
110 if ((u < 90) && (m_type != WEATHER_TYPE_FINE)) // Get worse
112 m_grade += 0.33333334f;
113 return true;
116 if (m_type != WEATHER_TYPE_FINE)
118 /// Radical change:
119 ///- if light -> heavy
120 ///- if medium -> change weather type
121 ///- if heavy -> 50% light, 50% change weather type
123 if (m_grade < 0.33333334f)
125 m_grade = 0.9999f; // go nuts
126 return true;
128 else
130 if (m_grade > 0.6666667f)
132 // Severe change, but how severe?
133 uint32 rnd = urand(0,99);
134 if (rnd < 50)
136 m_grade -= 0.6666667f;
137 return true;
140 m_type = WEATHER_TYPE_FINE; // clear up
141 m_grade = 0;
145 // At this point, only weather that isn't doing anything remains but that have weather data
146 uint32 chance1 = m_weatherChances->data[season].rainChance;
147 uint32 chance2 = chance1+ m_weatherChances->data[season].snowChance;
148 uint32 chance3 = chance2+ m_weatherChances->data[season].stormChance;
150 uint32 rnd = urand(0, 99);
151 if(rnd <= chance1)
152 m_type = WEATHER_TYPE_RAIN;
153 else if(rnd <= chance2)
154 m_type = WEATHER_TYPE_SNOW;
155 else if(rnd <= chance3)
156 m_type = WEATHER_TYPE_STORM;
157 else
158 m_type = WEATHER_TYPE_FINE;
160 /// New weather statistics (if not fine):
161 ///- 85% light
162 ///- 7% medium
163 ///- 7% heavy
164 /// If fine 100% sun (no fog)
166 if (m_type == WEATHER_TYPE_FINE)
168 m_grade = 0.0f;
170 else if (u < 90)
172 m_grade = rand_norm() * 0.3333f;
174 else
176 // Severe change, but how severe?
177 rnd = urand(0, 99);
178 if (rnd < 50)
179 m_grade = rand_norm() * 0.3333f + 0.3334f;
180 else
181 m_grade = rand_norm() * 0.3333f + 0.6667f;
184 // return true only in case weather changes
185 return m_type != old_type || m_grade != old_grade;
188 void Weather::SendWeatherUpdateToPlayer(Player *player)
190 WorldPacket data( SMSG_WEATHER, (4+4+4) );
192 data << uint32(GetWeatherState()) << (float)m_grade << uint8(0);
193 player->GetSession()->SendPacket( &data );
196 void Weather::SendFineWeatherUpdateToPlayer(Player *player)
198 WorldPacket data( SMSG_WEATHER, (4+4+4) );
200 data << (uint32)WEATHER_STATE_FINE << (float)0.0f << uint8(0);
201 player->GetSession()->SendPacket( &data );
204 /// Send the new weather to all players in the zone
205 bool Weather::UpdateWeather()
207 Player* player = sWorld.FindPlayerInZone(m_zone);
208 if(!player)
209 return false;
211 ///- Send the weather packet to all players in this zone
212 if (m_grade >= 1)
213 m_grade = 0.9999f;
214 else if (m_grade < 0)
215 m_grade = 0.0001f;
217 WeatherState state = GetWeatherState();
219 WorldPacket data( SMSG_WEATHER, (4+4+4) );
220 data << uint32(state) << (float)m_grade << uint8(0);
221 player->SendMessageToSet( &data, true );
223 ///- Log the event
224 char const* wthstr;
225 switch(state)
227 case WEATHER_STATE_LIGHT_RAIN:
228 wthstr = "light rain";
229 break;
230 case WEATHER_STATE_MEDIUM_RAIN:
231 wthstr = "medium rain";
232 break;
233 case WEATHER_STATE_HEAVY_RAIN:
234 wthstr = "heavy rain";
235 break;
236 case WEATHER_STATE_LIGHT_SNOW:
237 wthstr = "light snow";
238 break;
239 case WEATHER_STATE_MEDIUM_SNOW:
240 wthstr = "medium snow";
241 break;
242 case WEATHER_STATE_HEAVY_SNOW:
243 wthstr = "heavy snow";
244 break;
245 case WEATHER_STATE_LIGHT_SANDSTORM:
246 wthstr = "light sandstorm";
247 break;
248 case WEATHER_STATE_MEDIUM_SANDSTORM:
249 wthstr = "medium sandstorm";
250 break;
251 case WEATHER_STATE_HEAVY_SANDSTORM:
252 wthstr = "heavy sandstorm";
253 break;
254 case WEATHER_STATE_THUNDERS:
255 wthstr = "thunders";
256 break;
257 case WEATHER_STATE_BLACKRAIN:
258 wthstr = "blackrain";
259 break;
260 case WEATHER_STATE_FINE:
261 default:
262 wthstr = "fine";
263 break;
265 sLog.outDetail("Change the weather of zone %u to %s.", m_zone, wthstr);
267 return true;
270 /// Set the weather
271 void Weather::SetWeather(WeatherType type, float grade)
273 if(m_type == type && m_grade == grade)
274 return;
276 m_type = type;
277 m_grade = grade;
278 UpdateWeather();
281 /// Get the sound number associated with the current weather
282 WeatherState Weather::GetWeatherState() const
284 if (m_grade<0.27f)
285 return WEATHER_STATE_FINE;
287 switch(m_type)
289 case WEATHER_TYPE_RAIN:
290 if(m_grade<0.40f)
291 return WEATHER_STATE_LIGHT_RAIN;
292 else if(m_grade<0.70f)
293 return WEATHER_STATE_MEDIUM_RAIN;
294 else
295 return WEATHER_STATE_HEAVY_RAIN;
296 case WEATHER_TYPE_SNOW:
297 if(m_grade<0.40f)
298 return WEATHER_STATE_LIGHT_SNOW;
299 else if(m_grade<0.70f)
300 return WEATHER_STATE_MEDIUM_SNOW;
301 else
302 return WEATHER_STATE_HEAVY_SNOW;
303 case WEATHER_TYPE_STORM:
304 if(m_grade<0.40f)
305 return WEATHER_STATE_LIGHT_SANDSTORM;
306 else if(m_grade<0.70f)
307 return WEATHER_STATE_MEDIUM_SANDSTORM;
308 else
309 return WEATHER_STATE_HEAVY_SANDSTORM;
310 case WEATHER_TYPE_BLACKRAIN:
311 return WEATHER_STATE_BLACKRAIN;
312 case WEATHER_TYPE_THUNDERS:
313 return WEATHER_STATE_THUNDERS;
314 case WEATHER_TYPE_FINE:
315 default:
316 return WEATHER_STATE_FINE;