[10041] Use for spell 49145 and ranks for decrease SPELL_DIRECT_DAMAGE damage.
[getmangos.git] / src / game / World.cpp
blobabf273dce2c529f41b5cea2d609021abcc048594
1 /*
2 * Copyright (C) 2005-2010 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 "Common.h"
24 #include "Database/DatabaseEnv.h"
25 #include "Config/ConfigEnv.h"
26 #include "SystemConfig.h"
27 #include "Log.h"
28 #include "Opcodes.h"
29 #include "WorldSession.h"
30 #include "WorldPacket.h"
31 #include "Weather.h"
32 #include "Player.h"
33 #include "Vehicle.h"
34 #include "SkillExtraItems.h"
35 #include "SkillDiscovery.h"
36 #include "World.h"
37 #include "AccountMgr.h"
38 #include "AchievementMgr.h"
39 #include "AuctionHouseMgr.h"
40 #include "ObjectMgr.h"
41 #include "CreatureEventAIMgr.h"
42 #include "SpellMgr.h"
43 #include "Chat.h"
44 #include "DBCStores.h"
45 #include "LootMgr.h"
46 #include "ItemEnchantmentMgr.h"
47 #include "MapManager.h"
48 #include "ScriptCalls.h"
49 #include "CreatureAIRegistry.h"
50 #include "Policies/SingletonImp.h"
51 #include "BattleGroundMgr.h"
52 #include "TemporarySummon.h"
53 #include "VMapFactory.h"
54 #include "GameEventMgr.h"
55 #include "PoolManager.h"
56 #include "Database/DatabaseImpl.h"
57 #include "GridNotifiersImpl.h"
58 #include "CellImpl.h"
59 #include "InstanceSaveMgr.h"
60 #include "WaypointManager.h"
61 #include "GMTicketMgr.h"
62 #include "Util.h"
63 #include "CharacterDatabaseCleaner.h"
65 INSTANTIATE_SINGLETON_1( World );
67 volatile bool World::m_stopEvent = false;
68 uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
69 volatile uint32 World::m_worldLoopCounter = 0;
71 float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE;
72 float World::m_MaxVisibleDistanceInInctances = DEFAULT_VISIBILITY_INSTANCE;
73 float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS;
74 float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE;
76 float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
77 float World::m_VisibleUnitGreyDistance = 0;
78 float World::m_VisibleObjectGreyDistance = 0;
80 /// World constructor
81 World::World()
83 m_playerLimit = 0;
84 m_allowMovement = true;
85 m_ShutdownMask = 0;
86 m_ShutdownTimer = 0;
87 m_gameTime=time(NULL);
88 m_startTime=m_gameTime;
89 m_maxActiveSessionCount = 0;
90 m_maxQueuedSessionCount = 0;
91 m_resultQueue = NULL;
92 m_NextDailyQuestReset = 0;
93 m_NextWeeklyQuestReset = 0;
94 m_scheduledScripts = 0;
96 m_defaultDbcLocale = LOCALE_enUS;
97 m_availableDbcLocaleMask = 0;
99 for(int i = 0; i < CONFIG_UINT32_VALUE_COUNT; ++i)
100 m_configUint32Values[i] = 0;
102 for(int i = 0; i < CONFIG_INT32_VALUE_COUNT; ++i)
103 m_configInt32Values[i] = 0;
105 for(int i = 0; i < CONFIG_FLOAT_VALUE_COUNT; ++i)
106 m_configFloatValues[i] = 0.0f;
108 for(int i = 0; i < CONFIG_BOOL_VALUE_COUNT; ++i)
109 m_configBoolValues[i] = false;
112 /// World destructor
113 World::~World()
115 ///- Empty the kicked session set
116 while (!m_sessions.empty())
118 // not remove from queue, prevent loading new sessions
119 delete m_sessions.begin()->second;
120 m_sessions.erase(m_sessions.begin());
123 ///- Empty the WeatherMap
124 for (WeatherMap::const_iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
125 delete itr->second;
127 m_weathers.clear();
129 CliCommandHolder* command;
130 while (cliCmdQueue.next(command))
131 delete command;
133 VMAP::VMapFactory::clear();
135 if(m_resultQueue) delete m_resultQueue;
137 //TODO free addSessQueue
140 /// Find a player in a specified zone
141 Player* World::FindPlayerInZone(uint32 zone)
143 ///- circle through active sessions and return the first player found in the zone
144 SessionMap::const_iterator itr;
145 for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
147 if(!itr->second)
148 continue;
149 Player *player = itr->second->GetPlayer();
150 if(!player)
151 continue;
152 if( player->IsInWorld() && player->GetZoneId() == zone )
154 // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone.
155 return player;
158 return NULL;
161 /// Find a session by its id
162 WorldSession* World::FindSession(uint32 id) const
164 SessionMap::const_iterator itr = m_sessions.find(id);
166 if(itr != m_sessions.end())
167 return itr->second; // also can return NULL for kicked session
168 else
169 return NULL;
172 /// Remove a given session
173 bool World::RemoveSession(uint32 id)
175 ///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
176 SessionMap::const_iterator itr = m_sessions.find(id);
178 if(itr != m_sessions.end() && itr->second)
180 if (itr->second->PlayerLoading())
181 return false;
182 itr->second->KickPlayer();
185 return true;
188 void World::AddSession(WorldSession* s)
190 addSessQueue.add(s);
193 void
194 World::AddSession_ (WorldSession* s)
196 ASSERT (s);
198 //NOTE - Still there is race condition in WorldSession* being used in the Sockets
200 ///- kick already loaded player with same account (if any) and remove session
201 ///- if player is in loading and want to load again, return
202 if (!RemoveSession (s->GetAccountId ()))
204 s->KickPlayer ();
205 delete s; // session not added yet in session list, so not listed in queue
206 return;
209 // decrease session counts only at not reconnection case
210 bool decrease_session = true;
212 // if session already exist, prepare to it deleting at next world update
213 // NOTE - KickPlayer() should be called on "old" in RemoveSession()
215 SessionMap::const_iterator old = m_sessions.find(s->GetAccountId ());
217 if(old != m_sessions.end())
219 // prevent decrease sessions count if session queued
220 if(RemoveQueuedPlayer(old->second))
221 decrease_session = false;
222 // not remove replaced session form queue if listed
223 delete old->second;
227 m_sessions[s->GetAccountId ()] = s;
229 uint32 Sessions = GetActiveAndQueuedSessionCount ();
230 uint32 pLimit = GetPlayerAmountLimit ();
231 uint32 QueueSize = GetQueueSize (); //number of players in the queue
233 //so we don't count the user trying to
234 //login as a session and queue the socket that we are using
235 if(decrease_session)
236 --Sessions;
238 if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER )
240 AddQueuedPlayer (s);
241 UpdateMaxSessionCounters ();
242 DETAIL_LOG("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize);
243 return;
246 WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
247 packet << uint8 (AUTH_OK);
248 packet << uint32 (0); // BillingTimeRemaining
249 packet << uint8 (0); // BillingPlanFlags
250 packet << uint32 (0); // BillingTimeRested
251 packet << uint8 (s->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
252 s->SendPacket (&packet);
254 s->SendAddonsInfo();
256 WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
257 pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
258 s->SendPacket(&pkt);
260 s->SendTutorialsData();
262 UpdateMaxSessionCounters ();
264 // Updates the population
265 if (pLimit > 0)
267 float popu = float(GetActiveSessionCount()); // updated number of users on the server
268 popu /= pLimit;
269 popu *= 2;
270 loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
271 DETAIL_LOG("Server Population (%f).", popu);
275 int32 World::GetQueuePos(WorldSession* sess)
277 uint32 position = 1;
279 for(Queue::const_iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position)
280 if((*iter) == sess)
281 return position;
283 return 0;
286 void World::AddQueuedPlayer(WorldSession* sess)
288 sess->SetInQueue(true);
289 m_QueuedPlayer.push_back (sess);
291 // The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
292 WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + 4 + 1);
293 packet << uint8 (AUTH_WAIT_QUEUE);
294 packet << uint32 (0); // BillingTimeRemaining
295 packet << uint8 (0); // BillingPlanFlags
296 packet << uint32 (0); // BillingTimeRested
297 packet << uint8 (sess->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
298 packet << uint32(GetQueuePos (sess)); // position in queue
299 packet << uint8(0); // unk 3.3.0
300 sess->SendPacket (&packet);
303 bool World::RemoveQueuedPlayer(WorldSession* sess)
305 // sessions count including queued to remove (if removed_session set)
306 uint32 sessions = GetActiveSessionCount();
308 uint32 position = 1;
309 Queue::iterator iter = m_QueuedPlayer.begin();
311 // search to remove and count skipped positions
312 bool found = false;
314 for(;iter != m_QueuedPlayer.end(); ++iter, ++position)
316 if(*iter==sess)
318 sess->SetInQueue(false);
319 iter = m_QueuedPlayer.erase(iter);
320 found = true; // removing queued session
321 break;
325 // iter point to next socked after removed or end()
326 // position store position of removed socket and then new position next socket after removed
328 // if session not queued then we need decrease sessions count
329 if(!found && sessions)
330 --sessions;
332 // accept first in queue
333 if( (!m_playerLimit || (int32)sessions < m_playerLimit) && !m_QueuedPlayer.empty() )
335 WorldSession* pop_sess = m_QueuedPlayer.front();
336 pop_sess->SetInQueue(false);
337 pop_sess->SendAuthWaitQue(0);
338 pop_sess->SendAddonsInfo();
340 WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
341 pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
342 pop_sess->SendPacket(&pkt);
344 pop_sess->SendAccountDataTimes(GLOBAL_CACHE_MASK);
345 pop_sess->SendTutorialsData();
347 m_QueuedPlayer.pop_front();
349 // update iter to point first queued socket or end() if queue is empty now
350 iter = m_QueuedPlayer.begin();
351 position = 1;
354 // update position from iter to end()
355 // iter point to first not updated socket, position store new position
356 for(; iter != m_QueuedPlayer.end(); ++iter, ++position)
357 (*iter)->SendAuthWaitQue(position);
359 return found;
362 /// Find a Weather object by the given zoneid
363 Weather* World::FindWeather(uint32 id) const
365 WeatherMap::const_iterator itr = m_weathers.find(id);
367 if(itr != m_weathers.end())
368 return itr->second;
369 else
370 return 0;
373 /// Remove a Weather object for the given zoneid
374 void World::RemoveWeather(uint32 id)
376 // not called at the moment. Kept for completeness
377 WeatherMap::iterator itr = m_weathers.find(id);
379 if(itr != m_weathers.end())
381 delete itr->second;
382 m_weathers.erase(itr);
386 /// Add a Weather object to the list
387 Weather* World::AddWeather(uint32 zone_id)
389 WeatherZoneChances const* weatherChances = sObjectMgr.GetWeatherChances(zone_id);
391 // zone not have weather, ignore
392 if(!weatherChances)
393 return NULL;
395 Weather* w = new Weather(zone_id,weatherChances);
396 m_weathers[w->GetZone()] = w;
397 w->ReGenerate();
398 w->UpdateWeather();
399 return w;
402 /// Initialize config values
403 void World::LoadConfigSettings(bool reload)
405 if(reload)
407 if(!sConfig.Reload())
409 sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str());
410 return;
414 ///- Read the version of the configuration file and warn the user in case of emptiness or mismatch
415 uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
416 if(!confVersion)
418 sLog.outError("*****************************************************************************");
419 sLog.outError(" WARNING: mangosd.conf does not include a ConfVersion variable.");
420 sLog.outError(" Your configuration file may be out of date!");
421 sLog.outError("*****************************************************************************");
422 Log::WaitBeforeContinueIfNeed();
424 else
426 if (confVersion < _MANGOSDCONFVERSION)
428 sLog.outError("*****************************************************************************");
429 sLog.outError(" WARNING: Your mangosd.conf version indicates your conf file is out of date!");
430 sLog.outError(" Please check for updates, as your current default values may cause");
431 sLog.outError(" unexpected behavior.");
432 sLog.outError("*****************************************************************************");
433 Log::WaitBeforeContinueIfNeed();
437 ///- Read the player limit and the Message of the day from the config file
438 SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT), true );
439 SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) );
441 ///- Read all rates from the config file
442 setConfigPos(CONFIG_FLOAT_RATE_HEALTH, "Rate.Health", 1.0f);
443 setConfigPos(CONFIG_FLOAT_RATE_POWER_MANA, "Rate.Mana", 1.0f);
444 setConfig(CONFIG_FLOAT_RATE_POWER_RAGE_INCOME, "Rate.Rage.Income", 1.0f);
445 setConfigPos(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS, "Rate.Rage.Loss", 1.0f);
446 setConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME, "Rate.RunicPower.Income", 1.0f);
447 setConfigPos(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_LOSS, "Rate.RunicPower.Loss", 1.0f);
448 setConfig(CONFIG_FLOAT_RATE_POWER_FOCUS, "Rate.Focus", 1.0f);
449 setConfigPos(CONFIG_FLOAT_RATE_SKILL_DISCOVERY, "Rate.Skill.Discovery", 1.0f);
450 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_POOR, "Rate.Drop.Item.Poor", 1.0f);
451 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_NORMAL, "Rate.Drop.Item.Normal", 1.0f);
452 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_UNCOMMON, "Rate.Drop.Item.Uncommon", 1.0f);
453 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_RARE, "Rate.Drop.Item.Rare", 1.0f);
454 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_EPIC, "Rate.Drop.Item.Epic", 1.0f);
455 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY, "Rate.Drop.Item.Legendary", 1.0f);
456 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "Rate.Drop.Item.Artifact", 1.0f);
457 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f);
458 setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
459 setConfig(CONFIG_FLOAT_RATE_XP_KILL, "Rate.XP.Kill", 1.0f);
460 setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "Rate.XP.Quest", 1.0f);
461 setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
462 setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN, "Rate.Reputation.Gain", 1.0f);
463 setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL, "Rate.Reputation.LowLevel.Kill", 1.0f);
464 setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, "Rate.Reputation.LowLevel.Quest", 1.0f);
465 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_DAMAGE, "Rate.Creature.Normal.Damage", 1.0f);
466 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_DAMAGE, "Rate.Creature.Elite.Elite.Damage", 1.0f);
467 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_DAMAGE, "Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
468 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE, "Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f);
469 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_DAMAGE, "Rate.Creature.Elite.RARE.Damage", 1.0f);
470 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_HP, "Rate.Creature.Normal.HP", 1.0f);
471 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_HP, "Rate.Creature.Elite.Elite.HP", 1.0f);
472 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_HP, "Rate.Creature.Elite.RAREELITE.HP", 1.0f);
473 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_HP, "Rate.Creature.Elite.WORLDBOSS.HP", 1.0f);
474 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_HP, "Rate.Creature.Elite.RARE.HP", 1.0f);
475 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_SPELLDAMAGE, "Rate.Creature.Normal.SpellDamage", 1.0f);
476 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE, "Rate.Creature.Elite.Elite.SpellDamage", 1.0f);
477 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE, "Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f);
478 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE, "Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f);
479 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_SPELLDAMAGE, "Rate.Creature.Elite.RARE.SpellDamage", 1.0f);
480 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_AGGRO, "Rate.Creature.Aggro", 1.0f);
481 setConfig(CONFIG_FLOAT_RATE_REST_INGAME, "Rate.Rest.InGame", 1.0f);
482 setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY, "Rate.Rest.Offline.InTavernOrCity", 1.0f);
483 setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS, "Rate.Rest.Offline.InWilderness", 1.0f);
484 setConfigPos(CONFIG_FLOAT_RATE_DAMAGE_FALL, "Rate.Damage.Fall", 1.0f);
485 setConfigPos(CONFIG_FLOAT_RATE_AUCTION_TIME, "Rate.Auction.Time", 1.0f);
486 setConfig(CONFIG_FLOAT_RATE_AUCTION_DEPOSIT, "Rate.Auction.Deposit", 1.0f);
487 setConfig(CONFIG_FLOAT_RATE_AUCTION_CUT, "Rate.Auction.Cut", 1.0f);
488 setConfig(CONFIG_FLOAT_RATE_HONOR, "Rate.Honor",1.0f);
489 setConfigPos(CONFIG_FLOAT_RATE_MINING_AMOUNT, "Rate.Mining.Amount", 1.0f);
490 setConfigPos(CONFIG_FLOAT_RATE_MINING_NEXT, "Rate.Mining.Next", 1.0f);
491 setConfigPos(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME, "Rate.InstanceResetTime", 1.0f);
492 setConfigPos(CONFIG_FLOAT_RATE_TALENT, "Rate.Talent", 1.0f);
493 setConfigPos(CONFIG_FLOAT_RATE_CORPSE_DECAY_LOOTED, "Rate.Corpse.Decay.Looted", 0.1f);
495 setConfigMinMax(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE, "TargetPosRecalculateRange", 1.5f, CONTACT_DISTANCE, ATTACK_DISTANCE);
497 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE, "DurabilityLossChance.Damage", 0.5f);
498 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_ABSORB, "DurabilityLossChance.Absorb", 0.5f);
499 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_PARRY, "DurabilityLossChance.Parry", 0.05f);
500 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_BLOCK, "DurabilityLossChance.Block", 0.05f);
502 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_SAY, "ListenRange.Say", 25.0f);
503 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_YELL, "ListenRange.Yell", 300.0f);
504 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE, "ListenRange.TextEmote", 25.0f);
506 setConfigPos(CONFIG_FLOAT_GROUP_XP_DISTANCE, "MaxGroupXPDistance", 74.0f);
507 setConfigPos(CONFIG_FLOAT_SIGHT_GUARDER, "GuarderSight", 50.0f);
508 setConfigPos(CONFIG_FLOAT_SIGHT_MONSTER, "MonsterSight", 50.0f);
510 setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS, "CreatureFamilyAssistanceRadius", 10.0f);
511 setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS, "CreatureFamilyFleeAssistanceRadius", 30.0f);
513 ///- Read other configuration items from the config file
514 setConfigMinMax(CONFIG_UINT32_COMPRESSION, "Compression", 1, 1, 9);
515 setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
516 setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true);
517 setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true);
518 setConfigPos(CONFIG_UINT32_INTERVAL_SAVE, "PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS);
519 setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL);
520 setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "PlayerSave.Stats.SaveOnlyOnLogout", true);
522 setConfigMin(CONFIG_UINT32_INTERVAL_GRIDCLEAN, "GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS, MIN_GRID_DELAY);
523 if (reload)
524 sMapMgr.SetGridCleanUpDelay(getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN));
526 setConfigMin(CONFIG_UINT32_INTERVAL_MAPUPDATE, "MapUpdateInterval", 100, MIN_MAP_UPDATE_DELAY);
527 if (reload)
528 sMapMgr.SetMapUpdateInterval(getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
530 setConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER, "ChangeWeatherInterval", 10 * MINUTE * IN_MILLISECONDS);
532 if (configNoReload(reload, CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT))
533 setConfig(CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT);
535 if (configNoReload(reload, CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME))
536 setConfig(CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
538 if (configNoReload(reload, CONFIG_UINT32_GAME_TYPE, "GameType", 0))
539 setConfig(CONFIG_UINT32_GAME_TYPE, "GameType", 0);
541 if (configNoReload(reload, CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT))
542 setConfig(CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT);
544 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS, "AllowTwoSide.Accounts", true);
545 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT, "AllowTwoSide.Interaction.Chat", false);
546 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, "AllowTwoSide.Interaction.Channel", false);
547 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP, "AllowTwoSide.Interaction.Group", false);
548 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GUILD, "AllowTwoSide.Interaction.Guild", false);
549 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION, "AllowTwoSide.Interaction.Auction", false);
550 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL, "AllowTwoSide.Interaction.Mail", false);
551 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST, "AllowTwoSide.WhoList", false);
552 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND, "AllowTwoSide.AddFriend", false);
554 setConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES, "StrictPlayerNames", 0);
555 setConfig(CONFIG_UINT32_STRICT_CHARTER_NAMES, "StrictCharterNames", 0);
556 setConfig(CONFIG_UINT32_STRICT_PET_NAMES, "StrictPetNames", 0);
558 setConfigMinMax(CONFIG_UINT32_MIN_PLAYER_NAME, "MinPlayerName", 2, 1, MAX_PLAYER_NAME);
559 setConfigMinMax(CONFIG_UINT32_MIN_CHARTER_NAME, "MinCharterName", 2, 1, MAX_CHARTER_NAME);
560 setConfigMinMax(CONFIG_UINT32_MIN_PET_NAME, "MinPetName", 2, 1, MAX_PET_NAME);
562 setConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED, "CharactersCreatingDisabled", 0);
564 setConfigMinMax(CONFIG_UINT32_CHARACTERS_PER_REALM, "CharactersPerRealm", 10, 1, 10);
566 // must be after CONFIG_UINT32_CHARACTERS_PER_REALM
567 setConfigMin(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT, "CharactersPerAccount", 50, getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM));
569 setConfigMinMax(CONFIG_UINT32_HEROIC_CHARACTERS_PER_REALM, "HeroicCharactersPerRealm", 1, 1, 10);
571 setConfig(CONFIG_UINT32_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING, "MinLevelForHeroicCharacterCreating", 55);
573 setConfigMinMax(CONFIG_UINT32_SKIP_CINEMATICS, "SkipCinematics", 0, 0, 2);
575 if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL))
576 setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL);
578 setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
579 setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
581 setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT);
583 setConfigPos(CONFIG_UINT32_MAX_HONOR_POINTS, "MaxHonorPoints", 75000);
585 setConfigMinMax(CONFIG_UINT32_START_HONOR_POINTS, "StartHonorPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_HONOR_POINTS));
587 setConfigPos(CONFIG_UINT32_MAX_ARENA_POINTS, "MaxArenaPoints", 5000);
589 setConfigMinMax(CONFIG_UINT32_START_ARENA_POINTS, "StartArenaPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_ARENA_POINTS));
591 setConfig(CONFIG_BOOL_ALL_TAXI_PATHS, "AllFlightPaths", false);
593 setConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL, "Instance.IgnoreLevel", false);
594 setConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID, "Instance.IgnoreRaid", false);
596 setConfig(CONFIG_BOOL_CAST_UNSTUCK, "CastUnstuck", true);
597 setConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN, "MaxSpellCastsInChain", 10);
598 setConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR, "Instance.ResetTimeHour", 4);
599 setConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY, "Instance.UnloadDelay", 30 * MINUTE * IN_MILLISECONDS);
601 setConfig(CONFIG_UINT32_MAX_PRIMARY_TRADE_SKILL, "MaxPrimaryTradeSkill", 2);
602 setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS, "MinPetitionSigns", 9, 0, 9);
604 setConfig(CONFIG_UINT32_GM_LOGIN_STATE, "GM.LoginState", 2);
605 setConfig(CONFIG_UINT32_GM_VISIBLE_STATE, "GM.Visible", 2);
606 setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "GM.AcceptTickets", 2);
607 setConfig(CONFIG_UINT32_GM_CHAT, "GM.Chat", 2);
608 setConfig(CONFIG_UINT32_GM_WISPERING_TO, "GM.WhisperingTo", 2);
610 setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST, "GM.InGMList.Level", SEC_ADMINISTRATOR);
611 setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST, "GM.InWhoList.Level", SEC_ADMINISTRATOR);
612 setConfig(CONFIG_BOOL_GM_LOG_TRADE, "GM.LogTrade", false);
614 setConfigMinMax(CONFIG_UINT32_START_GM_LEVEL, "GM.StartLevel", 1, getConfig(CONFIG_UINT32_START_PLAYER_LEVEL), MAX_LEVEL);
615 setConfig(CONFIG_BOOL_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
616 setConfig(CONFIG_BOOL_GM_ALLOW_ACHIEVEMENT_GAINS, "GM.AllowAchievementGain", true);
618 setConfig(CONFIG_UINT32_GROUP_VISIBILITY, "Visibility.GroupMode", 0);
620 setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MailDeliveryDelay", HOUR);
622 setConfigPos(CONFIG_UINT32_UPTIME_UPDATE, "UpdateUptimeInterval", 10);
623 if (reload)
625 m_timers[WUPDATE_UPTIME].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE)*MINUTE*IN_MILLISECONDS);
626 m_timers[WUPDATE_UPTIME].Reset();
629 setConfig(CONFIG_UINT32_SKILL_CHANCE_ORANGE, "SkillChance.Orange", 100);
630 setConfig(CONFIG_UINT32_SKILL_CHANCE_YELLOW, "SkillChance.Yellow", 75);
631 setConfig(CONFIG_UINT32_SKILL_CHANCE_GREEN, "SkillChance.Green", 25);
632 setConfig(CONFIG_UINT32_SKILL_CHANCE_GREY, "SkillChance.Grey", 0);
634 setConfigPos(CONFIG_UINT32_SKILL_CHANCE_MINING_STEPS, "SkillChance.MiningSteps", 75);
635 setConfigPos(CONFIG_UINT32_SKILL_CHANCE_SKINNING_STEPS, "SkillChance.SkinningSteps", 75);
637 setConfig(CONFIG_BOOL_SKILL_PROSPECTING, "SkillChance.Prospecting", false);
638 setConfig(CONFIG_BOOL_SKILL_MILLING, "SkillChance.Milling", false);
640 setConfigPos(CONFIG_UINT32_SKILL_GAIN_CRAFTING, "SkillGain.Crafting", 1);
641 setConfigPos(CONFIG_UINT32_SKILL_GAIN_DEFENSE, "SkillGain.Defense", 1);
642 setConfigPos(CONFIG_UINT32_SKILL_GAIN_GATHERING, "SkillGain.Gathering", 1);
643 setConfig(CONFIG_UINT32_SKILL_GAIN_WEAPON, "SkillGain.Weapon", 1);
645 setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, "MaxOverspeedPings", 2);
646 if (getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) != 0 && getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) < 2)
648 sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.", getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS));
649 setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, 2);
652 setConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY, "SaveRespawnTimeImmediately", true);
653 setConfig(CONFIG_BOOL_WEATHER, "ActivateWeather", true);
655 setConfig(CONFIG_BOOL_ALWAYS_MAX_SKILL_FOR_LEVEL, "AlwaysMaxSkillForLevel", false);
657 if (configNoReload(reload, CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION))
658 setConfigMinMax(CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION, 0, MAX_EXPANSION);
660 setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_COUNT, "ChatFlood.MessageCount", 10);
661 setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_DELAY, "ChatFlood.MessageDelay", 1);
662 setConfig(CONFIG_UINT32_CHATFLOOD_MUTE_TIME, "ChatFlood.MuteTime", 10);
664 setConfig(CONFIG_BOOL_EVENT_ANNOUNCE, "Event.Announce", false);
666 setConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY, "CreatureFamilyAssistanceDelay", 1500);
667 setConfig(CONFIG_UINT32_CREATURE_FAMILY_FLEE_DELAY, "CreatureFamilyFleeDelay", 7000);
669 setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "WorldBossLevelDiff", 3);
671 // note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level MAX_LEVEL(100)
672 setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, "Quests.LowLevelHideDiff", 4);
673 if (getConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF) > MAX_LEVEL)
674 setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, MAX_LEVEL);
675 setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "Quests.HighLevelHideDiff", 7);
676 if (getConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF) > MAX_LEVEL)
677 setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, MAX_LEVEL);
679 setConfigMinMax(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR, "Quests.Daily.ResetHour", 6, 0, 23);
680 setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY, "Quests.Weekly.ResetWeekDay", 3, 0, 6);
681 setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR, "Quests.Weekly.ResetHour", 6, 0 , 23);
683 setConfig(CONFIG_BOOL_DETECT_POS_COLLISION, "DetectPosCollision", true);
685 setConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL, "Channel.RestrictedLfg", true);
686 setConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL, "Channel.SilentlyGMJoin", false);
688 setConfig(CONFIG_BOOL_TALENTS_INSPECTING, "TalentsInspecting", true);
689 setConfig(CONFIG_BOOL_CHAT_FAKE_MESSAGE_PREVENTING, "ChatFakeMessagePreventing", false);
691 setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY, "ChatStrictLinkChecking.Severity", 0);
692 setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_KICK, "ChatStrictLinkChecking.Kick", 0);
694 setConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW, "Corpse.EmptyLootShow", true);
695 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_NORMAL, "Corpse.Decay.NORMAL", 60);
696 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RARE, "Corpse.Decay.RARE", 300);
697 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_ELITE, "Corpse.Decay.ELITE", 300);
698 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RAREELITE, "Corpse.Decay.RAREELITE", 300);
699 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_WORLDBOSS, "Corpse.Decay.WORLDBOSS", 3600);
701 setConfig(CONFIG_INT32_DEATH_SICKNESS_LEVEL, "Death.SicknessLevel", 11);
703 setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVP, "Death.CorpseReclaimDelay.PvP", true);
704 setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVE, "Death.CorpseReclaimDelay.PvE", true);
705 setConfig(CONFIG_BOOL_DEATH_BONES_WORLD, "Death.Bones.World", true);
706 setConfig(CONFIG_BOOL_DEATH_BONES_BG_OR_ARENA, "Death.Bones.BattlegroundOrArena", true);
708 setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f);
710 // always use declined names in the russian client
711 if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN)
712 setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, true);
713 else
714 setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, "DeclinedNames", false);
716 setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, "Battleground.CastDeserter", true);
717 setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, "Battleground.QueueAnnouncer.Join", 0, 0, 2);
718 setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, "Battleground.QueueAnnouncer.Start", false);
719 setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE, "Battleground.InvitationType", 0);
720 setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER, "BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
721 setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS);
722 setConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE, "Arena.MaxRatingDifference", 150);
723 setConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER, "Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
724 setConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS, "Arena.AutoDistributePoints", false);
725 setConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS, "Arena.AutoDistributeInterval", 7);
726 setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_JOIN, "Arena.QueueAnnouncer.Join", false);
727 setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_EXIT, "Arena.QueueAnnouncer.Exit", false);
728 setConfig(CONFIG_UINT32_ARENA_SEASON_ID, "Arena.ArenaSeason.ID", 1);
729 setConfig(CONFIG_BOOL_ARENA_SEASON_IN_PROGRESS, "Arena.ArenaSeason.InProgress", true);
731 setConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET, "OffhandCheckAtTalentsReset", false);
733 setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false);
735 if(int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0))
737 // overwrite DB/old value
738 if(clientCacheId > 0)
740 setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION, clientCacheId);
741 sLog.outString("Client cache version set to: %u", clientCacheId);
743 else
744 sLog.outError("ClientCacheVersion can't be negative %d, ignored.", clientCacheId);
747 setConfig(CONFIG_UINT32_INSTANT_LOGOUT, "InstantLogout", SEC_MODERATOR);
749 setConfigMin(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT, "Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS, GUILD_EVENTLOG_MAX_RECORDS);
750 setConfigMin(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT, "Guild.BankEventLogRecordsCount", GUILD_BANK_MAX_LOGS, GUILD_BANK_MAX_LOGS);
752 setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_GMLEVEL, "TimerBar.Fatigue.GMLevel", SEC_CONSOLE);
753 setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_MAX, "TimerBar.Fatigue.Max", 60);
754 setConfig(CONFIG_UINT32_TIMERBAR_BREATH_GMLEVEL, "TimerBar.Breath.GMLevel", SEC_CONSOLE);
755 setConfig(CONFIG_UINT32_TIMERBAR_BREATH_MAX, "TimerBar.Breath.Max", 180);
756 setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL, "TimerBar.Fire.GMLevel", SEC_CONSOLE);
757 setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX, "TimerBar.Fire.Max", 1);
759 m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
760 if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
762 sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE);
763 m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
765 m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10);
766 if(m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
768 sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE);
769 m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
772 //visibility on continents
773 m_MaxVisibleDistanceOnContinents = sConfig.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE);
774 if(m_MaxVisibleDistanceOnContinents < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
776 sLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
777 m_MaxVisibleDistanceOnContinents = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
779 else if(m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
781 sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
782 m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
785 //visibility in instances
786 m_MaxVisibleDistanceInInctances = sConfig.GetFloatDefault("Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE);
787 if(m_MaxVisibleDistanceInInctances < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
789 sLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
790 m_MaxVisibleDistanceInInctances = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
792 else if(m_MaxVisibleDistanceInInctances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
794 sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
795 m_MaxVisibleDistanceInInctances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
798 //visibility in BG/Arenas
799 m_MaxVisibleDistanceInBGArenas = sConfig.GetFloatDefault("Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS);
800 if(m_MaxVisibleDistanceInBGArenas < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
802 sLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
803 m_MaxVisibleDistanceInBGArenas = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
805 else if(m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
807 sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
808 m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
811 m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE);
812 if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE)
814 sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
815 m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE;
817 else if(m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
819 sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
820 m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
822 m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE);
823 if(m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
825 sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
826 m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
829 ///- Load the CharDelete related config options
830 setConfigMinMax(CONFIG_UINT32_CHARDELETE_METHOD, "CharDelete.Method", 0, 0, 1);
831 setConfigMinMax(CONFIG_UINT32_CHARDELETE_MIN_LEVEL, "CharDelete.MinLevel", 0, 0, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
832 setConfigPos(CONFIG_UINT32_CHARDELETE_KEEP_DAYS, "CharDelete.KeepDays", 30);
834 ///- Read the "Data" directory from the config file
835 std::string dataPath = sConfig.GetStringDefault("DataDir","./");
836 if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' )
837 dataPath.append("/");
839 if(reload)
841 if(dataPath!=m_dataPath)
842 sLog.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%s).",m_dataPath.c_str());
844 else
846 m_dataPath = dataPath;
847 sLog.outString("Using DataDir %s",m_dataPath.c_str());
850 bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
851 bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
852 std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
853 std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", "");
854 VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
855 VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
856 VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str());
857 VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
858 sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight);
859 sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str());
860 sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");
863 /// Initialize the World
864 void World::SetInitialWorldSettings()
866 ///- Initialize the random number generator
867 srand((unsigned int)time(NULL));
869 ///- Time server startup
870 uint32 uStartTime = getMSTime();
872 ///- Initialize config settings
873 LoadConfigSettings();
875 ///- Init highest guids before any table loading to prevent using not initialized guids in some code.
876 sObjectMgr.SetHighestGuids();
878 ///- Check the existence of the map files for all races' startup areas.
879 if( !MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f)
880 ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
881 ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
882 ||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f)
883 ||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f)
884 ||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f)
885 ||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f)
886 ||m_configUint32Values[CONFIG_UINT32_EXPANSION] && (
887 !MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
889 sLog.outError("Correct *.map files not found in path '%smaps' or *.vmap/*vmdir files in '%svmaps'. Please place *.map/*.vmap/*.vmdir files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str());
890 exit(1);
893 ///- Loading strings. Getting no records means core load has to be canceled because no error message can be output.
894 sLog.outString();
895 sLog.outString("Loading MaNGOS strings...");
896 if (!sObjectMgr.LoadMangosStrings())
897 exit(1); // Error message displayed in function already
899 ///- Update the realm entry in the database with the realm type from the config file
900 //No SQL injection as values are treated as integers
902 // not send custom type REALM_FFA_PVP to realm list
903 uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_UINT32_GAME_TYPE);
904 uint32 realm_zone = getConfig(CONFIG_UINT32_REALM_ZONE);
905 loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
907 ///- Remove the bones (they should not exist in DB though) and old corpses after a restart
908 CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3*DAY);
910 ///- Load the DBC files
911 sLog.outString("Initialize data stores...");
912 LoadDBCStores(m_dataPath);
913 DetectDBCLang();
915 sLog.outString( "Loading Script Names...");
916 sObjectMgr.LoadScriptNames();
918 sLog.outString( "Loading InstanceTemplate..." );
919 sObjectMgr.LoadInstanceTemplate();
921 sLog.outString( "Loading SkillLineAbilityMultiMap Data..." );
922 sSpellMgr.LoadSkillLineAbilityMap();
924 ///- Clean up and pack instances
925 sLog.outString( "Cleaning up instances..." );
926 sInstanceSaveMgr.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
928 sLog.outString( "Packing instances..." );
929 sInstanceSaveMgr.PackInstances();
931 sLog.outString( "Packing groups..." );
932 sObjectMgr.PackGroupIds();
934 sLog.outString();
935 sLog.outString( "Loading Localization strings..." );
936 sObjectMgr.LoadCreatureLocales();
937 sObjectMgr.LoadGameObjectLocales();
938 sObjectMgr.LoadItemLocales();
939 sObjectMgr.LoadQuestLocales();
940 sObjectMgr.LoadNpcTextLocales();
941 sObjectMgr.LoadPageTextLocales();
942 sObjectMgr.LoadGossipMenuItemsLocales();
943 sObjectMgr.LoadPointOfInterestLocales();
944 sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
945 sLog.outString( ">>> Localization strings loaded" );
946 sLog.outString();
948 sLog.outString( "Loading Page Texts..." );
949 sObjectMgr.LoadPageTexts();
951 sLog.outString( "Loading Game Object Templates..." ); // must be after LoadPageTexts
952 sObjectMgr.LoadGameobjectInfo();
954 sLog.outString( "Loading Spell Chain Data..." );
955 sSpellMgr.LoadSpellChains();
957 sLog.outString( "Loading Spell Elixir types..." );
958 sSpellMgr.LoadSpellElixirs();
960 sLog.outString( "Loading Spell Learn Skills..." );
961 sSpellMgr.LoadSpellLearnSkills(); // must be after LoadSpellChains
963 sLog.outString( "Loading Spell Learn Spells..." );
964 sSpellMgr.LoadSpellLearnSpells();
966 sLog.outString( "Loading Spell Proc Event conditions..." );
967 sSpellMgr.LoadSpellProcEvents();
969 sLog.outString( "Loading Spell Bonus Data..." );
970 sSpellMgr.LoadSpellBonuses(); // must be after LoadSpellChains
972 sLog.outString( "Loading Spell Proc Item Enchant..." );
973 sSpellMgr.LoadSpellProcItemEnchant(); // must be after LoadSpellChains
975 sLog.outString( "Loading Aggro Spells Definitions...");
976 sSpellMgr.LoadSpellThreats();
978 sLog.outString( "Loading NPC Texts..." );
979 sObjectMgr.LoadGossipText();
981 sLog.outString( "Loading Item Random Enchantments Table..." );
982 LoadRandomEnchantmentsTable();
984 sLog.outString( "Loading Items..." ); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
985 sObjectMgr.LoadItemPrototypes();
987 sLog.outString( "Loading Creature Model Based Info Data..." );
988 sObjectMgr.LoadCreatureModelInfo();
990 sLog.outString( "Loading Equipment templates...");
991 sObjectMgr.LoadEquipmentTemplates();
993 sLog.outString( "Loading Creature templates..." );
994 sObjectMgr.LoadCreatureTemplates();
996 sLog.outString( "Loading SpellsScriptTarget...");
997 sSpellMgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
999 sLog.outString( "Loading ItemRequiredTarget...");
1000 sObjectMgr.LoadItemRequiredTarget();
1002 sLog.outString( "Loading Creature Reputation OnKill Data..." );
1003 sObjectMgr.LoadReputationOnKill();
1005 sLog.outString( "Loading Points Of Interest Data..." );
1006 sObjectMgr.LoadPointsOfInterest();
1008 sLog.outString( "Loading Creature Data..." );
1009 sObjectMgr.LoadCreatures();
1011 sLog.outString( "Loading pet levelup spells..." );
1012 sSpellMgr.LoadPetLevelupSpellMap();
1014 sLog.outString( "Loading pet default spell additional to levelup spells..." );
1015 sSpellMgr.LoadPetDefaultSpells();
1017 sLog.outString( "Loading Creature Addon Data..." );
1018 sLog.outString();
1019 sObjectMgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures()
1020 sLog.outString( ">>> Creature Addon Data loaded" );
1021 sLog.outString();
1023 sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances()
1024 sObjectMgr.LoadCreatureRespawnTimes();
1026 sLog.outString( "Loading Gameobject Data..." );
1027 sObjectMgr.LoadGameobjects();
1029 sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
1030 sObjectMgr.LoadGameobjectRespawnTimes();
1032 sLog.outString( "Loading Objects Pooling Data...");
1033 sPoolMgr.LoadFromDB();
1035 sLog.outString( "Loading Game Event Data...");
1036 sLog.outString();
1037 sGameEventMgr.LoadFromDB();
1038 sLog.outString( ">>> Game Event Data loaded" );
1039 sLog.outString();
1041 sLog.outString( "Loading Weather Data..." );
1042 sObjectMgr.LoadWeatherZoneChances();
1044 sLog.outString( "Loading Quests..." );
1045 sObjectMgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables
1047 sLog.outString( "Loading Quest POI" );
1048 sObjectMgr.LoadQuestPOI();
1050 sLog.outString( "Loading Quests Relations..." );
1051 sLog.outString();
1052 sObjectMgr.LoadQuestRelations(); // must be after quest load
1053 sLog.outString( ">>> Quests Relations loaded" );
1054 sLog.outString();
1056 sLog.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
1057 sObjectMgr.LoadNPCSpellClickSpells();
1059 sLog.outString( "Loading SpellArea Data..." ); // must be after quest load
1060 sSpellMgr.LoadSpellAreas();
1062 sLog.outString( "Loading AreaTrigger definitions..." );
1063 sObjectMgr.LoadAreaTriggerTeleports(); // must be after item template load
1065 sLog.outString( "Loading Quest Area Triggers..." );
1066 sObjectMgr.LoadQuestAreaTriggers(); // must be after LoadQuests
1068 sLog.outString( "Loading Tavern Area Triggers..." );
1069 sObjectMgr.LoadTavernAreaTriggers();
1071 sLog.outString( "Loading AreaTrigger script names..." );
1072 sObjectMgr.LoadAreaTriggerScripts();
1074 sLog.outString( "Loading Graveyard-zone links...");
1075 sObjectMgr.LoadGraveyardZones();
1077 sLog.outString( "Loading Spell target coordinates..." );
1078 sSpellMgr.LoadSpellTargetPositions();
1080 sLog.outString( "Loading spell pet auras..." );
1081 sSpellMgr.LoadSpellPetAuras();
1083 sLog.outString( "Loading Player Create Info & Level Stats..." );
1084 sLog.outString();
1085 sObjectMgr.LoadPlayerInfo();
1086 sLog.outString( ">>> Player Create Info & Level Stats loaded" );
1087 sLog.outString();
1089 sLog.outString( "Loading Exploration BaseXP Data..." );
1090 sObjectMgr.LoadExplorationBaseXP();
1092 sLog.outString( "Loading Pet Name Parts..." );
1093 sObjectMgr.LoadPetNames();
1095 CharacterDatabaseCleaner::CleanDatabase();
1097 sLog.outString( "Loading the max pet number..." );
1098 sObjectMgr.LoadPetNumber();
1100 sLog.outString( "Loading pet level stats..." );
1101 sObjectMgr.LoadPetLevelInfo();
1103 sLog.outString( "Loading Player Corpses..." );
1104 sObjectMgr.LoadCorpses();
1106 sLog.outString( "Loading Player level dependent mail rewards..." );
1107 sObjectMgr.LoadMailLevelRewards();
1109 sLog.outString( "Loading Loot Tables..." );
1110 sLog.outString();
1111 LoadLootTables();
1112 sLog.outString( ">>> Loot Tables loaded" );
1113 sLog.outString();
1115 sLog.outString( "Loading Skill Discovery Table..." );
1116 LoadSkillDiscoveryTable();
1118 sLog.outString( "Loading Skill Extra Item Table..." );
1119 LoadSkillExtraItemTable();
1121 sLog.outString( "Loading Skill Fishing base level requirements..." );
1122 sObjectMgr.LoadFishingBaseSkillLevel();
1124 sLog.outString( "Loading Achievements..." );
1125 sLog.outString();
1126 sAchievementMgr.LoadAchievementReferenceList();
1127 sAchievementMgr.LoadAchievementCriteriaList();
1128 sAchievementMgr.LoadAchievementCriteriaRequirements();
1129 sAchievementMgr.LoadRewards();
1130 sAchievementMgr.LoadRewardLocales();
1131 sAchievementMgr.LoadCompletedAchievements();
1132 sLog.outString( ">>> Achievements loaded" );
1133 sLog.outString();
1135 ///- Load dynamic data tables from the database
1136 sLog.outString( "Loading Auctions..." );
1137 sLog.outString();
1138 sAuctionMgr.LoadAuctionItems();
1139 sAuctionMgr.LoadAuctions();
1140 sLog.outString( ">>> Auctions loaded" );
1141 sLog.outString();
1143 sLog.outString( "Loading Guilds..." );
1144 sObjectMgr.LoadGuilds();
1146 sLog.outString( "Loading ArenaTeams..." );
1147 sObjectMgr.LoadArenaTeams();
1149 sLog.outString( "Loading Groups..." );
1150 sObjectMgr.LoadGroups();
1152 sLog.outString( "Loading ReservedNames..." );
1153 sObjectMgr.LoadReservedPlayersNames();
1155 sLog.outString( "Loading GameObjects for quests..." );
1156 sObjectMgr.LoadGameObjectForQuests();
1158 sLog.outString( "Loading BattleMasters..." );
1159 sBattleGroundMgr.LoadBattleMastersEntry();
1161 sLog.outString( "Loading BattleGround event indexes..." );
1162 sBattleGroundMgr.LoadBattleEventIndexes();
1164 sLog.outString( "Loading GameTeleports..." );
1165 sObjectMgr.LoadGameTele();
1167 sLog.outString( "Loading Npc Text Id..." );
1168 sObjectMgr.LoadNpcTextId(); // must be after load Creature and NpcText
1170 sLog.outString( "Loading Gossip scripts..." );
1171 sObjectMgr.LoadGossipScripts(); // must be before gossip menu options
1173 sLog.outString( "Loading Gossip menus..." );
1174 sObjectMgr.LoadGossipMenu();
1176 sLog.outString( "Loading Gossip menu options..." );
1177 sObjectMgr.LoadGossipMenuItems();
1179 sLog.outString( "Loading Vendors..." );
1180 sObjectMgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate
1182 sLog.outString( "Loading Trainers..." );
1183 sObjectMgr.LoadTrainerSpell(); // must be after load CreatureTemplate
1185 sLog.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement
1186 sObjectMgr.LoadCreatureMovementScripts();
1188 sLog.outString( "Loading Waypoints..." );
1189 sLog.outString();
1190 sWaypointMgr.Load();
1192 sLog.outString( "Loading GM tickets...");
1193 sTicketMgr.LoadGMTickets();
1195 ///- Handle outdated emails (delete/return)
1196 sLog.outString( "Returning old mails..." );
1197 sObjectMgr.ReturnOrDeleteOldMails(false);
1199 ///- Load and initialize scripts
1200 sLog.outString( "Loading Scripts..." );
1201 sLog.outString();
1202 sObjectMgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1203 sObjectMgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1204 sObjectMgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
1205 sObjectMgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data)
1206 sObjectMgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data)
1207 sLog.outString( ">>> Scripts loaded" );
1208 sLog.outString();
1210 sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
1211 sObjectMgr.LoadDbScriptStrings();
1213 sLog.outString( "Loading CreatureEventAI Texts...");
1214 sEventAIMgr.LoadCreatureEventAI_Texts(false); // false, will checked in LoadCreatureEventAI_Scripts
1216 sLog.outString( "Loading CreatureEventAI Summons...");
1217 sEventAIMgr.LoadCreatureEventAI_Summons(false); // false, will checked in LoadCreatureEventAI_Scripts
1219 sLog.outString( "Loading CreatureEventAI Scripts...");
1220 sEventAIMgr.LoadCreatureEventAI_Scripts();
1222 sLog.outString( "Initializing Scripts..." );
1223 if(!LoadScriptingModule())
1224 exit(1);
1226 ///- Initialize game time and timers
1227 sLog.outString( "DEBUG:: Initialize game time and timers" );
1228 m_gameTime = time(NULL);
1229 m_startTime=m_gameTime;
1231 tm local;
1232 time_t curr;
1233 time(&curr);
1234 local=*(localtime(&curr)); // dereference and assign
1235 char isoDate[128];
1236 sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
1237 local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
1239 loginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)",
1240 realmID, uint64(m_startTime), isoDate);
1242 m_timers[WUPDATE_OBJECTS].SetInterval(0);
1243 m_timers[WUPDATE_SESSIONS].SetInterval(0);
1244 m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
1245 m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
1246 m_timers[WUPDATE_UPTIME].SetInterval(m_configUint32Values[CONFIG_UINT32_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
1247 //Update "uptime" table based on configuration entry in minutes.
1248 m_timers[WUPDATE_CORPSES].SetInterval(3*HOUR*IN_MILLISECONDS);
1249 m_timers[WUPDATE_DELETECHARS].SetInterval(DAY*IN_MILLISECONDS); // check for chars to delete every day
1251 //to set mailtimer to return mails every day between 4 and 5 am
1252 //mailtimer is increased when updating auctions
1253 //one second is 1000 -(tested on win system)
1254 mail_timer = uint32((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * IN_MILLISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
1255 //1440
1256 mail_timer_expires = uint32( (DAY * IN_MILLISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
1257 DEBUG_LOG("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
1259 ///- Initialize static helper structures
1260 AIRegistry::Initialize();
1261 Player::InitVisibleBits();
1263 ///- Initialize MapManager
1264 sLog.outString( "Starting Map System" );
1265 sMapMgr.Initialize();
1267 ///- Initialize Battlegrounds
1268 sLog.outString( "Starting BattleGround System" );
1269 sBattleGroundMgr.CreateInitialBattleGrounds();
1270 sBattleGroundMgr.InitAutomaticArenaPointDistribution();
1272 //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
1273 sLog.outString( "Loading Transports..." );
1274 sMapMgr.LoadTransports();
1276 sLog.outString("Deleting expired bans..." );
1277 loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
1279 sLog.outString("Calculate next daily quest reset time..." );
1280 InitDailyQuestResetTime();
1282 sLog.outString("Calculate next weekly quest reset time..." );
1283 InitWeeklyQuestResetTime();
1285 sLog.outString("Starting objects Pooling system..." );
1286 sPoolMgr.Initialize();
1288 sLog.outString("Starting Game Event system..." );
1289 uint32 nextGameEvent = sGameEventMgr.Initialize();
1290 m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); //depend on next event
1292 // Delete all characters which have been deleted X days before
1293 Player::DeleteOldCharacters();
1295 sLog.outString( "WORLD: World initialized" );
1297 uint32 uStartInterval = getMSTimeDiff(uStartTime, getMSTime());
1298 sLog.outString( "SERVER STARTUP TIME: %i minutes %i seconds", uStartInterval / 60000, (uStartInterval % 60000) / 1000 );
1301 void World::DetectDBCLang()
1303 uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255);
1305 if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE)
1307 sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE);
1308 m_lang_confid = LOCALE_enUS;
1311 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1);
1313 std::string availableLocalsStr;
1315 int default_locale = MAX_LOCALE;
1316 for (int i = MAX_LOCALE-1; i >= 0; --i)
1318 if ( strlen(race->name[i]) > 0) // check by race names
1320 default_locale = i;
1321 m_availableDbcLocaleMask |= (1 << i);
1322 availableLocalsStr += localeNames[i];
1323 availableLocalsStr += " ";
1327 if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE &&
1328 (m_availableDbcLocaleMask & (1 << m_lang_confid)) )
1330 default_locale = m_lang_confid;
1333 if(default_locale >= MAX_LOCALE)
1335 sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)");
1336 exit(1);
1339 m_defaultDbcLocale = LocaleConstant(default_locale);
1341 sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
1342 sLog.outString();
1345 /// Update the World !
1346 void World::Update(uint32 diff)
1348 ///- Update the different timers
1349 for(int i = 0; i < WUPDATE_COUNT; ++i)
1351 if (m_timers[i].GetCurrent()>=0)
1352 m_timers[i].Update(diff);
1353 else
1354 m_timers[i].SetCurrent(0);
1357 ///- Update the game time and check for shutdown time
1358 _UpdateGameTime();
1360 /// Handle daily quests reset time
1361 if (m_gameTime > m_NextDailyQuestReset)
1362 ResetDailyQuests();
1364 /// Handle weekly quests reset time
1365 if (m_gameTime > m_NextWeeklyQuestReset)
1366 ResetWeeklyQuests();
1368 /// <ul><li> Handle auctions when the timer has passed
1369 if (m_timers[WUPDATE_AUCTIONS].Passed())
1371 m_timers[WUPDATE_AUCTIONS].Reset();
1373 ///- Update mails (return old mails with item, or delete them)
1374 //(tested... works on win)
1375 if (++mail_timer > mail_timer_expires)
1377 mail_timer = 0;
1378 sObjectMgr.ReturnOrDeleteOldMails(true);
1381 ///- Handle expired auctions
1382 sAuctionMgr.Update();
1385 /// <li> Handle session updates when the timer has passed
1386 if (m_timers[WUPDATE_SESSIONS].Passed())
1388 m_timers[WUPDATE_SESSIONS].Reset();
1390 UpdateSessions(diff);
1393 /// <li> Handle weather updates when the timer has passed
1394 if (m_timers[WUPDATE_WEATHERS].Passed())
1396 m_timers[WUPDATE_WEATHERS].Reset();
1398 ///- Send an update signal to Weather objects
1399 WeatherMap::iterator itr, next;
1400 for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next)
1402 next = itr;
1403 ++next;
1405 ///- and remove Weather objects for zones with no player
1406 //As interval > WorldTick
1407 if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval()))
1409 delete itr->second;
1410 m_weathers.erase(itr);
1414 /// <li> Update uptime table
1415 if (m_timers[WUPDATE_UPTIME].Passed())
1417 uint32 tmpDiff = uint32(m_gameTime - m_startTime);
1418 uint32 maxClientsNum = GetMaxActiveSessionCount();
1420 m_timers[WUPDATE_UPTIME].Reset();
1421 loginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime));
1424 /// <li> Handle all other objects
1425 if (m_timers[WUPDATE_OBJECTS].Passed())
1427 m_timers[WUPDATE_OBJECTS].Reset();
1428 ///- Update objects when the timer has passed (maps, transport, creatures,...)
1429 sMapMgr.Update(diff); // As interval = 0
1431 sBattleGroundMgr.Update(diff);
1434 ///- Delete all characters which have been deleted X days before
1435 if (m_timers[WUPDATE_DELETECHARS].Passed())
1437 m_timers[WUPDATE_DELETECHARS].Reset();
1438 Player::DeleteOldCharacters();
1441 // execute callbacks from sql queries that were queued recently
1442 UpdateResultQueue();
1444 ///- Erase corpses once every 20 minutes
1445 if (m_timers[WUPDATE_CORPSES].Passed())
1447 m_timers[WUPDATE_CORPSES].Reset();
1449 sObjectAccessor.RemoveOldCorpses();
1452 ///- Process Game events when necessary
1453 if (m_timers[WUPDATE_EVENTS].Passed())
1455 m_timers[WUPDATE_EVENTS].Reset(); // to give time for Update() to be processed
1456 uint32 nextGameEvent = sGameEventMgr.Update();
1457 m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
1458 m_timers[WUPDATE_EVENTS].Reset();
1461 /// </ul>
1462 ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
1463 sMapMgr.RemoveAllObjectsInRemoveList();
1465 // update the instance reset times
1466 sInstanceSaveMgr.Update();
1468 // And last, but not least handle the issued cli commands
1469 ProcessCliCommands();
1472 /// Send a packet to all players (except self if mentioned)
1473 void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
1475 SessionMap::const_iterator itr;
1476 for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1478 if (itr->second &&
1479 itr->second->GetPlayer() &&
1480 itr->second->GetPlayer()->IsInWorld() &&
1481 itr->second != self &&
1482 (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
1484 itr->second->SendPacket(packet);
1489 namespace MaNGOS
1491 class WorldWorldTextBuilder
1493 public:
1494 typedef std::vector<WorldPacket*> WorldPacketList;
1495 explicit WorldWorldTextBuilder(int32 textId, va_list* args = NULL) : i_textId(textId), i_args(args) {}
1496 void operator()(WorldPacketList& data_list, int32 loc_idx)
1498 char const* text = sObjectMgr.GetMangosString(i_textId,loc_idx);
1500 if(i_args)
1502 // we need copy va_list before use or original va_list will corrupted
1503 va_list ap;
1504 va_copy(ap,*i_args);
1506 char str [2048];
1507 vsnprintf(str,2048,text, ap );
1508 va_end(ap);
1510 do_helper(data_list,&str[0]);
1512 else
1513 do_helper(data_list,(char*)text);
1515 private:
1516 char* lineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; }
1517 void do_helper(WorldPacketList& data_list, char* text)
1519 char* pos = text;
1521 while(char* line = lineFromMessage(pos))
1523 WorldPacket* data = new WorldPacket();
1525 uint32 lineLength = (line ? strlen(line) : 0) + 1;
1527 data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
1528 *data << uint8(CHAT_MSG_SYSTEM);
1529 *data << uint32(LANG_UNIVERSAL);
1530 *data << uint64(0);
1531 *data << uint32(0); // can be chat msg group or something
1532 *data << uint64(0);
1533 *data << uint32(lineLength);
1534 *data << line;
1535 *data << uint8(0);
1537 data_list.push_back(data);
1541 int32 i_textId;
1542 va_list* i_args;
1544 } // namespace MaNGOS
1546 /// Send a System Message to all players (except self if mentioned)
1547 void World::SendWorldText(int32 string_id, ...)
1549 va_list ap;
1550 va_start(ap, string_id);
1552 MaNGOS::WorldWorldTextBuilder wt_builder(string_id, &ap);
1553 MaNGOS::LocalizedPacketListDo<MaNGOS::WorldWorldTextBuilder> wt_do(wt_builder);
1554 for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1556 if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
1557 continue;
1559 wt_do(itr->second->GetPlayer());
1562 va_end(ap);
1565 /// DEPRICATED, only for debug purpose. Send a System Message to all players (except self if mentioned)
1566 void World::SendGlobalText(const char* text, WorldSession *self)
1568 WorldPacket data;
1570 // need copy to prevent corruption by strtok call in LineFromMessage original string
1571 char* buf = mangos_strdup(text);
1572 char* pos = buf;
1574 while(char* line = ChatHandler::LineFromMessage(pos))
1576 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
1577 SendGlobalMessage(&data, self);
1580 delete [] buf;
1583 /// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
1584 void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
1586 SessionMap::const_iterator itr;
1587 for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1589 if (itr->second &&
1590 itr->second->GetPlayer() &&
1591 itr->second->GetPlayer()->IsInWorld() &&
1592 itr->second->GetPlayer()->GetZoneId() == zone &&
1593 itr->second != self &&
1594 (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
1596 itr->second->SendPacket(packet);
1601 /// Send a System Message to all players in the zone (except self if mentioned)
1602 void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team)
1604 WorldPacket data;
1605 ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL);
1606 SendZoneMessage(zone, &data, self,team);
1609 /// Kick (and save) all players
1610 void World::KickAll()
1612 m_QueuedPlayer.clear(); // prevent send queue update packet and login queued sessions
1614 // session not removed at kick and will removed in next update tick
1615 for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1616 itr->second->KickPlayer();
1619 /// Kick (and save) all players with security level less `sec`
1620 void World::KickAllLess(AccountTypes sec)
1622 // session not removed at kick and will removed in next update tick
1623 for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1624 if(itr->second->GetSecurity() < sec)
1625 itr->second->KickPlayer();
1628 /// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
1629 BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
1631 loginDatabase.escape_string(nameOrIP);
1632 loginDatabase.escape_string(reason);
1633 std::string safe_author=author;
1634 loginDatabase.escape_string(safe_author);
1636 uint32 duration_secs = TimeStringToSecs(duration);
1637 QueryResult *resultAccounts = NULL; //used for kicking
1639 ///- Update the database with ban information
1640 switch(mode)
1642 case BAN_IP:
1643 //No SQL injection as strings are escaped
1644 resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
1645 loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str());
1646 break;
1647 case BAN_ACCOUNT:
1648 //No SQL injection as string is escaped
1649 resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
1650 break;
1651 case BAN_CHARACTER:
1652 //No SQL injection as string is escaped
1653 resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str());
1654 break;
1655 default:
1656 return BAN_SYNTAX_ERROR;
1659 if(!resultAccounts)
1661 if(mode==BAN_IP)
1662 return BAN_SUCCESS; // ip correctly banned but nobody affected (yet)
1663 else
1664 return BAN_NOTFOUND; // Nobody to ban
1667 ///- Disconnect all affected players (for IP it can be several)
1670 Field* fieldsAccount = resultAccounts->Fetch();
1671 uint32 account = fieldsAccount->GetUInt32();
1673 if(mode!=BAN_IP)
1675 //No SQL injection as strings are escaped
1676 loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
1677 account,duration_secs,safe_author.c_str(),reason.c_str());
1680 if (WorldSession* sess = FindSession(account))
1681 if(std::string(sess->GetPlayerName()) != author)
1682 sess->KickPlayer();
1684 while( resultAccounts->NextRow() );
1686 delete resultAccounts;
1687 return BAN_SUCCESS;
1690 /// Remove a ban from an account or IP address
1691 bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
1693 if (mode == BAN_IP)
1695 loginDatabase.escape_string(nameOrIP);
1696 loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
1698 else
1700 uint32 account = 0;
1701 if (mode == BAN_ACCOUNT)
1702 account = sAccountMgr.GetId (nameOrIP);
1703 else if (mode == BAN_CHARACTER)
1704 account = sObjectMgr.GetPlayerAccountIdByPlayerName (nameOrIP);
1706 if (!account)
1707 return false;
1709 //NO SQL injection as account is uint32
1710 loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
1712 return true;
1715 /// Update the game time
1716 void World::_UpdateGameTime()
1718 ///- update the time
1719 time_t thisTime = time(NULL);
1720 uint32 elapsed = uint32(thisTime - m_gameTime);
1721 m_gameTime = thisTime;
1723 ///- if there is a shutdown timer
1724 if(!m_stopEvent && m_ShutdownTimer > 0 && elapsed > 0)
1726 ///- ... and it is overdue, stop the world (set m_stopEvent)
1727 if( m_ShutdownTimer <= elapsed )
1729 if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
1730 m_stopEvent = true; // exist code already set
1731 else
1732 m_ShutdownTimer = 1; // minimum timer value to wait idle state
1734 ///- ... else decrease it and if necessary display a shutdown countdown to the users
1735 else
1737 m_ShutdownTimer -= elapsed;
1739 ShutdownMsg();
1744 /// Shutdown the server
1745 void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
1747 // ignore if server shutdown at next tick
1748 if(m_stopEvent)
1749 return;
1751 m_ShutdownMask = options;
1752 m_ExitCode = exitcode;
1754 ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions)
1755 if(time==0)
1757 if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
1758 m_stopEvent = true; // exist code already set
1759 else
1760 m_ShutdownTimer = 1; //So that the session count is re-evaluated at next world tick
1762 ///- Else set the shutdown timer and warn users
1763 else
1765 m_ShutdownTimer = time;
1766 ShutdownMsg(true);
1770 /// Display a shutdown message to the user(s)
1771 void World::ShutdownMsg(bool show, Player* player)
1773 // not show messages for idle shutdown mode
1774 if(m_ShutdownMask & SHUTDOWN_MASK_IDLE)
1775 return;
1777 ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
1778 if ( show ||
1779 (m_ShutdownTimer < 10) ||
1780 // < 30 sec; every 5 sec
1781 (m_ShutdownTimer<30 && (m_ShutdownTimer % 5 )==0) ||
1782 // < 5 min ; every 1 min
1783 (m_ShutdownTimer<5*MINUTE && (m_ShutdownTimer % MINUTE )==0) ||
1784 // < 30 min ; every 5 min
1785 (m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) ||
1786 // < 12 h ; every 1 h
1787 (m_ShutdownTimer<12*HOUR && (m_ShutdownTimer % HOUR )==0) ||
1788 // > 12 h ; every 12 h
1789 (m_ShutdownTimer>12*HOUR && (m_ShutdownTimer % (12*HOUR) )==0))
1791 std::string str = secsToTimeString(m_ShutdownTimer);
1793 ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
1795 SendServerMessage(msgid,str.c_str(),player);
1796 DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"),str.c_str());
1800 /// Cancel a planned server shutdown
1801 void World::ShutdownCancel()
1803 // nothing cancel or too later
1804 if(!m_ShutdownTimer || m_stopEvent)
1805 return;
1807 ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
1809 m_ShutdownMask = 0;
1810 m_ShutdownTimer = 0;
1811 m_ExitCode = SHUTDOWN_EXIT_CODE; // to default value
1812 SendServerMessage(msgid);
1814 DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"));
1817 /// Send a server message to the user(s)
1818 void World::SendServerMessage(ServerMessageType type, const char *text, Player* player)
1820 WorldPacket data(SMSG_SERVER_MESSAGE, 50); // guess size
1821 data << uint32(type);
1822 if(type <= SERVER_MSG_STRING)
1823 data << text;
1825 if(player)
1826 player->GetSession()->SendPacket(&data);
1827 else
1828 SendGlobalMessage( &data );
1831 void World::UpdateSessions( uint32 diff )
1833 ///- Add new sessions
1834 WorldSession* sess;
1835 while(addSessQueue.next(sess))
1836 AddSession_ (sess);
1838 ///- Then send an update signal to remaining ones
1839 for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
1841 next = itr;
1842 ++next;
1843 ///- and remove not active sessions from the list
1844 if(!itr->second->Update(diff)) // As interval = 0
1846 RemoveQueuedPlayer (itr->second);
1847 delete itr->second;
1848 m_sessions.erase(itr);
1853 // This handles the issued and queued CLI/RA commands
1854 void World::ProcessCliCommands()
1856 CliCommandHolder::Print* zprint = NULL;
1857 void* callbackArg = NULL;
1858 CliCommandHolder* command;
1859 while (cliCmdQueue.next(command))
1861 DEBUG_LOG("CLI command under processing...");
1862 zprint = command->m_print;
1863 callbackArg = command->m_callbackArg;
1864 CliHandler handler(command->m_cliAccountId, command->m_cliAccessLevel, callbackArg, zprint);
1865 handler.ParseCommands(command->m_command);
1867 if(command->m_commandFinished)
1868 command->m_commandFinished(callbackArg, !handler.HasSentErrorMessage());
1870 delete command;
1874 void World::InitResultQueue()
1876 m_resultQueue = new SqlResultQueue;
1877 CharacterDatabase.SetResultQueue(m_resultQueue);
1880 void World::UpdateResultQueue()
1882 m_resultQueue->Update();
1885 void World::UpdateRealmCharCount(uint32 accountId)
1887 CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId,
1888 "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId);
1891 void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId)
1893 if (resultCharCount)
1895 Field *fields = resultCharCount->Fetch();
1896 uint32 charCount = fields[0].GetUInt32();
1897 delete resultCharCount;
1898 loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
1899 loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
1903 void World::InitWeeklyQuestResetTime()
1905 QueryResult * result = CharacterDatabase.Query("SELECT NextWeeklyQuestResetTime FROM saved_variables");
1906 if (!result)
1907 m_NextWeeklyQuestReset = time_t(time(NULL)); // game time not yet init
1908 else
1909 m_NextWeeklyQuestReset = time_t((*result)[0].GetUInt64());
1911 // generate time by config
1912 time_t curTime = time(NULL);
1913 tm localTm = *localtime(&curTime);
1915 int week_day_offset = localTm.tm_wday - int(getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY));
1917 // current week reset time
1918 localTm.tm_hour = getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR);
1919 localTm.tm_min = 0;
1920 localTm.tm_sec = 0;
1921 time_t nextWeekResetTime = mktime(&localTm);
1922 nextWeekResetTime -= week_day_offset * DAY; // move time to proper day
1924 // next reset time before current moment
1925 if (curTime >= nextWeekResetTime)
1926 nextWeekResetTime += WEEK;
1928 // normalize reset time
1929 m_NextWeeklyQuestReset = m_NextWeeklyQuestReset < curTime ? nextWeekResetTime - WEEK : nextWeekResetTime;
1931 if (!result)
1932 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextWeeklyQuestResetTime) VALUES ('"UI64FMTD"')", uint64(m_NextWeeklyQuestReset));
1933 else
1934 delete result;
1937 void World::InitDailyQuestResetTime()
1939 QueryResult * result = CharacterDatabase.Query("SELECT NextDailyQuestResetTime FROM saved_variables");
1940 if (!result)
1941 m_NextDailyQuestReset = time_t(time(NULL)); // game time not yet init
1942 else
1943 m_NextDailyQuestReset = time_t((*result)[0].GetUInt64());
1945 // generate time by config
1946 time_t curTime = time(NULL);
1947 tm localTm = *localtime(&curTime);
1948 localTm.tm_hour = getConfig(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR);
1949 localTm.tm_min = 0;
1950 localTm.tm_sec = 0;
1952 // current day reset time
1953 time_t nextDayResetTime = mktime(&localTm);
1955 // next reset time before current moment
1956 if (curTime >= nextDayResetTime)
1957 nextDayResetTime += DAY;
1959 // normalize reset time
1960 m_NextDailyQuestReset = m_NextDailyQuestReset < curTime ? nextDayResetTime - DAY : nextDayResetTime;
1962 if (!result)
1963 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextDailyQuestResetTime) VALUES ('"UI64FMTD"')", uint64(m_NextDailyQuestReset));
1964 else
1965 delete result;
1968 void World::ResetDailyQuests()
1970 DETAIL_LOG("Daily quests reset for all characters.");
1971 CharacterDatabase.Execute("DELETE FROM character_queststatus_daily");
1972 for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1973 if (itr->second->GetPlayer())
1974 itr->second->GetPlayer()->ResetDailyQuestStatus();
1976 m_NextDailyQuestReset = time_t(m_NextDailyQuestReset + DAY);
1977 CharacterDatabase.PExecute("UPDATE saved_variables SET NextDailyQuestResetTime = '"UI64FMTD"'", uint64(m_NextDailyQuestReset));
1980 void World::ResetWeeklyQuests()
1982 DETAIL_LOG("Weekly quests reset for all characters.");
1983 CharacterDatabase.Execute("DELETE FROM character_queststatus_weekly");
1984 for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
1985 if (itr->second->GetPlayer())
1986 itr->second->GetPlayer()->ResetWeeklyQuestStatus();
1988 m_NextWeeklyQuestReset = time_t(m_NextWeeklyQuestReset + WEEK);
1989 CharacterDatabase.PExecute("UPDATE saved_variables SET NextWeeklyQuestResetTime = '"UI64FMTD"'", uint64(m_NextWeeklyQuestReset));
1992 void World::SetPlayerLimit( int32 limit, bool needUpdate )
1994 if (limit < -SEC_ADMINISTRATOR)
1995 limit = -SEC_ADMINISTRATOR;
1997 // lock update need
1998 bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit);
2000 m_playerLimit = limit;
2002 if (db_update_need)
2003 loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
2006 void World::UpdateMaxSessionCounters()
2008 m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size()));
2009 m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size()));
2012 void World::LoadDBVersion()
2014 QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version, cache_id FROM db_version LIMIT 1");
2015 if(result)
2017 Field* fields = result->Fetch();
2019 m_DBVersion = fields[0].GetCppString();
2020 m_CreatureEventAIVersion = fields[1].GetCppString();
2022 // will be overwrite by config values if different and non-0
2023 setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION, fields[2].GetUInt32());
2024 delete result;
2027 if(m_DBVersion.empty())
2028 m_DBVersion = "Unknown world database.";
2030 if(m_CreatureEventAIVersion.empty())
2031 m_CreatureEventAIVersion = "Unknown creature EventAI.";
2034 void World::setConfig(eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
2036 setConfig(index, sConfig.GetIntDefault(fieldname,defvalue));
2039 void World::setConfig(eConfigInt32Values index, char const* fieldname, int32 defvalue)
2041 setConfig(index, sConfig.GetIntDefault(fieldname,defvalue));
2044 void World::setConfig(eConfigFloatValues index, char const* fieldname, float defvalue)
2046 setConfig(index, sConfig.GetFloatDefault(fieldname,defvalue));
2049 void World::setConfig( eConfigBoolValues index, char const* fieldname, bool defvalue )
2051 setConfig(index, sConfig.GetBoolDefault(fieldname,defvalue));
2054 void World::setConfigPos(eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
2056 setConfig(index, fieldname, defvalue);
2057 if (int32(getConfig(index)) < 0)
2059 sLog.outError("%s (%i) can't be negative. Using %u instead.", fieldname, int32(getConfig(index)), defvalue);
2060 setConfig(index, defvalue);
2064 void World::setConfigPos(eConfigFloatValues index, char const* fieldname, float defvalue)
2066 setConfig(index, fieldname, defvalue);
2067 if (getConfig(index) < 0.0f)
2069 sLog.outError("%s (%f) can't be negative. Using %f instead.", fieldname, getConfig(index), defvalue);
2070 setConfig(index, defvalue);
2074 void World::setConfigMin(eConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue)
2076 setConfig(index, fieldname, defvalue);
2077 if (getConfig(index) < minvalue)
2079 sLog.outError("%s (%u) must be >= %u. Using %u instead.", fieldname, getConfig(index), minvalue, minvalue);
2080 setConfig(index, minvalue);
2084 void World::setConfigMin(eConfigInt32Values index, char const* fieldname, int32 defvalue, int32 minvalue)
2086 setConfig(index, fieldname, defvalue);
2087 if (getConfig(index) < minvalue)
2089 sLog.outError("%s (%i) must be >= %i. Using %i instead.", fieldname, getConfig(index), minvalue, minvalue);
2090 setConfig(index, minvalue);
2094 void World::setConfigMin(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue)
2096 setConfig(index, fieldname, defvalue);
2097 if (getConfig(index) < minvalue)
2099 sLog.outError("%s (%f) must be >= %f. Using %f instead.", fieldname, getConfig(index), minvalue, minvalue);
2100 setConfig(index, minvalue);
2104 void World::setConfigMinMax(eConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue)
2106 setConfig(index, fieldname, defvalue);
2107 if (getConfig(index) < minvalue)
2109 sLog.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
2110 setConfig(index, minvalue);
2112 else if (getConfig(index) > maxvalue)
2114 sLog.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
2115 setConfig(index, maxvalue);
2119 void World::setConfigMinMax(eConfigInt32Values index, char const* fieldname, int32 defvalue, int32 minvalue, int32 maxvalue)
2121 setConfig(index, fieldname, defvalue);
2122 if (getConfig(index) < minvalue)
2124 sLog.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
2125 setConfig(index, minvalue);
2127 else if (getConfig(index) > maxvalue)
2129 sLog.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
2130 setConfig(index, maxvalue);
2134 void World::setConfigMinMax(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue, float maxvalue)
2136 setConfig(index, fieldname, defvalue);
2137 if (getConfig(index) < minvalue)
2139 sLog.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
2140 setConfig(index, minvalue);
2142 else if (getConfig(index) > maxvalue)
2144 sLog.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
2145 setConfig(index, maxvalue);
2149 bool World::configNoReload(bool reload, eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
2151 if (!reload)
2152 return true;
2154 uint32 val = sConfig.GetIntDefault(fieldname, defvalue);
2155 if (val != getConfig(index))
2156 sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%u).", fieldname, getConfig(index));
2158 return false;
2161 bool World::configNoReload(bool reload, eConfigInt32Values index, char const* fieldname, int32 defvalue)
2163 if (!reload)
2164 return true;
2166 int32 val = sConfig.GetIntDefault(fieldname, defvalue);
2167 if (val != getConfig(index))
2168 sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%i).", fieldname, getConfig(index));
2170 return false;
2173 bool World::configNoReload(bool reload, eConfigFloatValues index, char const* fieldname, float defvalue)
2175 if (!reload)
2176 return true;
2178 float val = sConfig.GetFloatDefault(fieldname, defvalue);
2179 if (val != getConfig(index))
2180 sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%f).", fieldname, getConfig(index));
2182 return false;
2185 bool World::configNoReload(bool reload, eConfigBoolValues index, char const* fieldname, bool defvalue)
2187 if (!reload)
2188 return true;
2190 bool val = sConfig.GetBoolDefault(fieldname, defvalue);
2191 if (val != getConfig(index))
2192 sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%s).", fieldname, getConfig(index) ? "'true'" : "'false'");
2194 return false;