OregonCore  revision 3611e8a-git
Your Favourite TBC server
Weather.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Weather.h"
19 #include "WorldPacket.h"
20 #include "WorldSession.h"
21 #include "Player.h"
22 #include "World.h"
23 #include "ObjectMgr.h"
24 #include "Log.h"
25 #include "Util.h"
26 
27 // Create the Weather object
28 Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone(zone), m_weatherChances(weatherChances)
29 {
32  m_grade = 0;
33 
34  sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (1000 * MINUTE)));
35 }
36 
37 // Launch a weather update
38 bool Weather::Update(time_t diff)
39 {
40  if (m_timer.GetCurrent() >= 0)
41  m_timer.Update(diff);
42  else m_timer.SetCurrent(0);
43 
44  // If the timer has passed, ReGenerate the weather
45  if (m_timer.Passed())
46  {
47  m_timer.Reset();
48  // update only if Regenerate has changed the weather
49  if (ReGenerate())
50  {
51  // Weather will be removed if not updated (no players in zone anymore)
52  if (!UpdateWeather())
53  return false;
54  }
55  }
56  return true;
57 }
58 
59 // Calculate the new weather
61 {
62  if (!m_weatherChances)
63  {
65  m_grade = 0.0f;
66  return false;
67  }
68 
69  // Weather statistics:
70  // 30% - no change
71  // 30% - weather gets better (if not fine) or change weather type
72  // 30% - weather worsens (if not fine)
73  // 10% - radical change (if not fine)
74  uint32 u = urand(0, 99);
75 
76  if (u < 30)
77  return false;
78 
79  // remember old values
80  WeatherType old_type = m_type;
81  float old_grade = m_grade;
82 
83  //78 days between January 1st and March 20nd; 365/4=91 days by season
84  // season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html
85  time_t gtime = sWorld.GetGameTime();
86  struct tm* ltime = localtime(&gtime);
87  uint32 season = ((ltime->tm_yday - 78 + 365) / 91) % 4;
88 
89  static char const* seasonName[WEATHER_SEASONS] = { "spring", "summer", "fall", "winter" };
90 
91  sLog.outDebug("Generating a change in %s weather for zone %u.", seasonName[season], m_zone);
92 
93  if ((u < 60) && (m_grade < 0.33333334f)) // Get fair
94  {
96  m_grade = 0.0f;
97  }
98 
99  if ((u < 60) && (m_type != WEATHER_TYPE_FINE)) // Get better
100  {
101  m_grade -= 0.33333334f;
102  return true;
103  }
104 
105  if ((u < 90) && (m_type != WEATHER_TYPE_FINE)) // Get worse
106  {
107  m_grade += 0.33333334f;
108  return true;
109  }
110 
111  if (m_type != WEATHER_TYPE_FINE)
112  {
113  // Radical change:
114  // if light -> heavy
115  // if medium -> change weather type
116  // if heavy -> 50% light, 50% change weather type
117 
118  if (m_grade < 0.33333334f)
119  {
120  m_grade = 0.9999f; // go nuts
121  return true;
122  }
123  else
124  {
125  if (m_grade > 0.6666667f)
126  {
127  // Severe change, but how severe?
128  uint32 rnd = urand(0, 99);
129  if (rnd < 50)
130  {
131  m_grade -= 0.6666667f;
132  return true;
133  }
134  }
135  m_type = WEATHER_TYPE_FINE; // clear up
136  m_grade = 0;
137  }
138  }
139 
140  // At this point, only weather that isn't doing anything remains but that have weather data
141  uint32 chance1 = m_weatherChances->data[season].rainChance;
142  uint32 chance2 = chance1 + m_weatherChances->data[season].snowChance;
143  uint32 chance3 = chance2 + m_weatherChances->data[season].stormChance;
144 
145  uint32 rnd = urand(1, 100);
146  if (rnd <= chance1)
148  else if (rnd <= chance2)
150  else if (rnd <= chance3)
152  else
154 
155  // New weather statistics (if not fine):
156  // 85% light
157  // 7% medium
158  // 7% heavy
159  // If fine 100% sun (no fog)
160 
161  if (m_type == WEATHER_TYPE_FINE)
162  m_grade = 0.0f;
163  else if (u < 90)
164  m_grade = rand_norm() * 0.3333f;
165  else
166  {
167  // Severe change, but how severe?
168  rnd = urand(0, 99);
169  if (rnd < 50)
170  m_grade = rand_norm() * 0.3333f + 0.3334f;
171  else
172  m_grade = rand_norm() * 0.3333f + 0.6667f;
173  }
174 
175  // return true only in case weather changes
176  return m_type != old_type || m_grade != old_grade;
177 }
178 
180 {
181  WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
182  data << uint32(GetWeatherState());
183  data << (float)m_grade;
184  data << uint8(0); // 1 for instant change, 0 for smooth change
185  player->GetSession()->SendPacket(&data);
186 }
187 
189 {
190  WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
191  data << uint32(WEATHER_STATE_FINE);
192  data << (float)0.0f;
193  data << uint8(0); // 1 for instant change, 0 for smooth change
194  player->GetSession()->SendPacket(&data);
195 }
196 
197 // Send the new weather to all players in the zone
199 {
200  // Send the weather packet to all players in this zone
201  if (m_grade >= 1)
202  m_grade = 0.9999f;
203  else if (m_grade < 0)
204  m_grade = 0.0001f;
205 
206  WeatherState state = GetWeatherState();
207 
208  WorldPacket data(SMSG_WEATHER, (4 + 4 + 1));
209  data << uint32(state);
210  data << (float)m_grade;
211  data << uint8(0); // 1 for instant change, 0 for smooth change
212 
213  //- Returns false if there were no players found to update
214  if (!sWorld.SendZoneMessage(m_zone, &data))
215  return false;
216 
217  // Log the event
218  char const* wthstr;
219  switch (state)
220  {
222  wthstr = "light rain";
223  break;
225  wthstr = "medium rain";
226  break;
228  wthstr = "heavy rain";
229  break;
231  wthstr = "light snow";
232  break;
234  wthstr = "medium snow";
235  break;
237  wthstr = "heavy snow";
238  break;
240  wthstr = "light sandstorm";
241  break;
243  wthstr = "medium sandstorm";
244  break;
246  wthstr = "heavy sandstorm";
247  break;
249  wthstr = "thunders";
250  break;
252  wthstr = "blackrain";
253  break;
254  case WEATHER_STATE_FINE:
255  default:
256  wthstr = "fine";
257  break;
258  }
259  sLog.outDetail("Change the weather of zone %u to %s.", m_zone, wthstr);
260 
261  return true;
262 }
263 
264 // Set the weather
265 void Weather::SetWeather(WeatherType type, float grade)
266 {
267  if (m_type == type && m_grade == grade)
268  return;
269 
270  m_type = type;
271  m_grade = grade;
272  UpdateWeather();
273 }
274 
275 // Get the sound number associated with the current weather
277 {
278  if (m_grade < 0.27f)
279  return WEATHER_STATE_FINE;
280 
281  switch (m_type)
282  {
283  case WEATHER_TYPE_RAIN:
284  if (m_grade < 0.40f)
286  else if (m_grade < 0.70f)
288  else
290  case WEATHER_TYPE_SNOW:
291  if (m_grade < 0.40f)
293  else if (m_grade < 0.70f)
295  else
297  case WEATHER_TYPE_STORM:
298  if (m_grade < 0.40f)
300  else if (m_grade < 0.70f)
302  else
307  return WEATHER_STATE_THUNDERS;
308  case WEATHER_TYPE_FINE:
309  default:
310  return WEATHER_STATE_FINE;
311  }
312 }
313 
float m_grade
Definition: Weather.h:66
time_t GetInterval() const
Definition: Timer.h:126
WeatherState
Definition: Weather.h:27
uint32 m_zone
Definition: Weather.h:64
time_t GetCurrent() const
Definition: Timer.h:130
void Update(time_t diff)
Definition: Timer.h:104
#define sLog
Log class singleton.
Definition: Log.h:187
bool Passed()
Definition: Timer.h:109
void SendPacket(WorldPacket const *packet)
void SetInterval(time_t interval)
Definition: Timer.h:122
Definition: Common.h:179
WeatherZoneChances const * m_weatherChances
Definition: Weather.h:68
bool ReGenerate()
Definition: Weather.cpp:60
ACE_UINT8 uint8
Definition: Define.h:73
Weather(uint32 zone, WeatherZoneChances const *weatherChances)
Definition: Weather.cpp:28
WeatherType m_type
Definition: Weather.h:65
WeatherState GetWeatherState() const
Definition: Weather.cpp:276
WeatherSeasonChances data[WEATHER_SEASONS]
Definition: ObjectMgr.h:470
bool UpdateWeather()
Definition: Weather.cpp:198
void Reset()
Definition: Timer.h:113
static void SendFineWeatherUpdateToPlayer(Player *player)
Definition: Weather.cpp:188
IntervalTimer m_timer
Definition: Weather.h:67
#define WEATHER_SEASONS
Definition: ObjectMgr.h:460
void SendWeatherUpdateToPlayer(Player *player)
Definition: Weather.cpp:179
double rand_norm(void)
Definition: Util.cpp:86
WeatherType
WorldSession * GetSession() const
Definition: Player.h:1959
#define sWorld
Definition: World.h:860
void SetCurrent(time_t current)
Definition: Timer.h:118
ACE_UINT32 uint32
Definition: Define.h:71
void SetWeather(WeatherType type, float grade)
Definition: Weather.cpp:265
Definition: Player.h:922
bool Update(time_t diff)
Definition: Weather.cpp:38
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:71