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