root/trunk/src/game/World.cpp @ 122

Revision 122, 106.1 kB (checked in by yumileroy, 17 years ago)

[svn] Fix a compile error about M_PI_2.
Update Felmyst script to test new setActive function.
Fix the bug that priest's fear is unbreakable (dirty hack before find the correct way).
(some unfinished unused content included, just ignore them, will finish them later)

Original author: megamage
Date: 2008-10-27 10:57:53-05:00

Line 
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 "Common.h"
26//#include "WorldSocket.h"
27#include "Database/DatabaseEnv.h"
28#include "Config/ConfigEnv.h"
29#include "SystemConfig.h"
30#include "Log.h"
31#include "Opcodes.h"
32#include "WorldSession.h"
33#include "WorldPacket.h"
34#include "Weather.h"
35#include "Player.h"
36#include "SkillExtraItems.h"
37#include "SkillDiscovery.h"
38#include "World.h"
39#include "AccountMgr.h"
40#include "ObjectMgr.h"
41#include "SpellMgr.h"
42#include "Chat.h"
43#include "Database/DBCStores.h"
44#include "LootMgr.h"
45#include "ItemEnchantmentMgr.h"
46#include "MapManager.h"
47#include "ScriptCalls.h"
48#include "CreatureAIRegistry.h"
49#include "Policies/SingletonImp.h"
50#include "BattleGroundMgr.h"
51#include "OutdoorPvPMgr.h"
52#include "TemporarySummon.h"
53#include "WaypointMovementGenerator.h"
54#include "VMapFactory.h"
55#include "GlobalEvents.h"
56#include "GameEvent.h"
57#include "Database/DatabaseImpl.h"
58#include "GridNotifiersImpl.h"
59#include "CellImpl.h"
60#include "InstanceSaveMgr.h"
61#include "WaypointManager.h"
62#include "Util.h"
63#include "Language.h"
64
65INSTANTIATE_SINGLETON_1( World );
66
67volatile bool World::m_stopEvent = false;
68volatile uint32 World::m_worldLoopCounter = 0;
69
70float World::m_MaxVisibleDistanceForCreature  = DEFAULT_VISIBILITY_DISTANCE;
71float World::m_MaxVisibleDistanceForPlayer    = DEFAULT_VISIBILITY_DISTANCE;
72float World::m_MaxVisibleDistanceForObject    = DEFAULT_VISIBILITY_DISTANCE;
73float World::m_MaxVisibleDistanceInFlight     = DEFAULT_VISIBILITY_DISTANCE;
74float World::m_VisibleUnitGreyDistance        = 0;
75float World::m_VisibleObjectGreyDistance      = 0;
76
77// ServerMessages.dbc
78enum ServerMessageType
79{
80    SERVER_MSG_SHUTDOWN_TIME      = 1,
81    SERVER_MSG_RESTART_TIME       = 2,
82    SERVER_MSG_STRING             = 3,
83    SERVER_MSG_SHUTDOWN_CANCELLED = 4,
84    SERVER_MSG_RESTART_CANCELLED  = 5
85};
86
87struct ScriptAction
88{
89    uint64 sourceGUID;
90    uint64 targetGUID;
91    uint64 ownerGUID;                                       // owner of source if source is item
92    ScriptInfo const* script;                               // pointer to static script data
93};
94
95/// World constructor
96World::World()
97{
98    m_playerLimit = 0;
99    m_allowMovement = true;
100    m_ShutdownMask = 0;
101    m_ShutdownTimer = 0;
102    m_gameTime=time(NULL);
103    m_startTime=m_gameTime;
104    m_maxActiveSessionCount = 0;
105    m_maxQueuedSessionCount = 0;
106    m_resultQueue = NULL;
107    m_NextDailyQuestReset = 0;
108
109    m_defaultDbcLocale = LOCALE_enUS;
110    m_availableDbcLocaleMask = 0;
111}
112
113/// World destructor
114World::~World()
115{
116    ///- Empty the kicked session set
117    for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr)
118        delete *itr;
119
120    m_kicked_sessions.clear();
121
122    ///- Empty the WeatherMap
123    for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
124        delete itr->second;
125
126    m_weathers.clear();
127
128    VMAP::VMapFactory::clear();
129
130    if(m_resultQueue) delete m_resultQueue;
131   
132    //TODO free addSessQueue
133}
134
135/// Find a player in a specified zone
136Player* World::FindPlayerInZone(uint32 zone)
137{
138    ///- circle through active sessions and return the first player found in the zone
139    SessionMap::iterator itr;
140    for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
141    {
142        if(!itr->second)
143            continue;
144        Player *player = itr->second->GetPlayer();
145        if(!player)
146            continue;
147        if( player->IsInWorld() && player->GetZoneId() == zone )
148        {
149            // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone.
150            return player;
151        }
152    }
153    return NULL;
154}
155
156/// Find a session by its id
157WorldSession* World::FindSession(uint32 id) const
158{
159    SessionMap::const_iterator itr = m_sessions.find(id);
160
161    if(itr != m_sessions.end())
162        return itr->second;                                 // also can return NULL for kicked session
163    else
164        return NULL;
165}
166
167/// Remove a given session
168bool World::RemoveSession(uint32 id)
169{
170    ///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
171    SessionMap::iterator itr = m_sessions.find(id);
172
173    if(itr != m_sessions.end() && itr->second)
174    {
175        if (itr->second->PlayerLoading())
176            return false;
177        itr->second->KickPlayer();
178    }
179
180    return true;
181}
182
183void World::AddSession(WorldSession* s)
184{
185  addSessQueue.add(s);
186}
187
188void
189World::AddSession_ (WorldSession* s)
190{
191  ASSERT (s);
192
193  //NOTE - Still there is race condition in WorldSession* being used in the Sockets
194
195  ///- kick already loaded player with same account (if any) and remove session
196  ///- if player is in loading and want to load again, return
197  if (!RemoveSession (s->GetAccountId ()))
198    {
199      s->KickPlayer ();
200      m_kicked_sessions.insert (s);
201      return;
202    }
203
204  WorldSession* old = m_sessions[s->GetAccountId ()];
205  m_sessions[s->GetAccountId ()] = s;
206
207  // if session already exist, prepare to it deleting at next world update
208  // NOTE - KickPlayer() should be called on "old" in RemoveSession()
209  if (old)
210    m_kicked_sessions.insert (old);
211
212  uint32 Sessions = GetActiveAndQueuedSessionCount ();
213  uint32 pLimit = GetPlayerAmountLimit ();
214  uint32 QueueSize = GetQueueSize (); //number of players in the queue
215  bool inQueue = false;
216  //so we don't count the user trying to
217  //login as a session and queue the socket that we are using
218  --Sessions;
219
220  if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER )
221    {
222      AddQueuedPlayer (s);
223      UpdateMaxSessionCounters ();
224      sLog.outDetail ("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize);
225      return;
226    }
227 
228  WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
229  packet << uint8 (AUTH_OK);
230  packet << uint32 (0); // unknown random value...
231  packet << uint8 (0);
232  packet << uint32 (0);
233  packet << uint8 (s->Expansion () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account
234  s->SendPacket (&packet);
235
236  UpdateMaxSessionCounters ();
237
238  // Updates the population
239  if (pLimit > 0)
240    {
241      float popu = GetActiveSessionCount (); //updated number of users on the server
242      popu /= pLimit;
243      popu *= 2;
244      loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
245      sLog.outDetail ("Server Population (%f).", popu);
246    }
247}
248
249int32 World::GetQueuePos(WorldSession* sess)
250{
251    uint32 position = 1;
252
253    for(Queue::iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position)
254        if((*iter) == sess)
255            return position;
256
257    return 0;
258}
259
260void World::AddQueuedPlayer(WorldSession* sess)
261{
262    m_QueuedPlayer.push_back (sess);
263   
264    // The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
265    WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
266    packet << uint8 (AUTH_WAIT_QUEUE);
267    packet << uint32 (0); // unknown random value...
268    packet << uint8 (0);
269    packet << uint32 (0);
270    packet << uint8 (sess->Expansion () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account
271    packet << uint32(GetQueuePos (sess));
272    sess->SendPacket (&packet);
273   
274    //sess->SendAuthWaitQue (GetQueuePos (sess));
275}
276
277void World::RemoveQueuedPlayer(WorldSession* sess)
278{
279    // sessions count including queued to remove (if removed_session set)
280    uint32 sessions = GetActiveSessionCount();
281
282    uint32 position = 1;
283    Queue::iterator iter = m_QueuedPlayer.begin();
284
285    // if session not queued then we need decrease sessions count (Remove socked callet before session removing from session list)
286    bool decrease_session = true;
287
288    // search to remove and count skipped positions
289    for(;iter != m_QueuedPlayer.end(); ++iter, ++position)
290    {
291        if(*iter==sess)
292        {
293            Queue::iterator iter2 = iter;
294            ++iter;
295            m_QueuedPlayer.erase(iter2);
296            decrease_session = false;                       // removing queued session
297            break;
298        }
299    }
300
301    // iter point to next socked after removed or end()
302    // position store position of removed socket and then new position next socket after removed
303
304    // decrease for case session queued for removing
305    if(decrease_session && sessions)
306        --sessions;
307
308    // accept first in queue
309    if( (!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty() )
310    {
311        WorldSession * socket = m_QueuedPlayer.front();
312        socket->SendAuthWaitQue(0);
313        m_QueuedPlayer.pop_front();
314
315        // update iter to point first queued socket or end() if queue is empty now
316        iter = m_QueuedPlayer.begin();
317        position = 1;
318    }
319
320    // update position from iter to end()
321    // iter point to first not updated socket, position store new position
322    for(; iter != m_QueuedPlayer.end(); ++iter, ++position)
323        (*iter)->SendAuthWaitQue(position);
324}
325
326/// Find a Weather object by the given zoneid
327Weather* World::FindWeather(uint32 id) const
328{
329    WeatherMap::const_iterator itr = m_weathers.find(id);
330
331    if(itr != m_weathers.end())
332        return itr->second;
333    else
334        return 0;
335}
336
337/// Remove a Weather object for the given zoneid
338void World::RemoveWeather(uint32 id)
339{
340    // not called at the moment. Kept for completeness
341    WeatherMap::iterator itr = m_weathers.find(id);
342
343    if(itr != m_weathers.end())
344    {
345        delete itr->second;
346        m_weathers.erase(itr);
347    }
348}
349
350/// Add a Weather object to the list
351Weather* World::AddWeather(uint32 zone_id)
352{
353    WeatherZoneChances const* weatherChances = objmgr.GetWeatherChances(zone_id);
354
355    // zone not have weather, ignore
356    if(!weatherChances)
357        return NULL;
358
359    Weather* w = new Weather(zone_id,weatherChances);
360    m_weathers[w->GetZone()] = w;
361    w->ReGenerate();
362    w->UpdateWeather();
363    return w;
364}
365
366/// Initialize config values
367void World::LoadConfigSettings(bool reload)
368{
369    if(reload)
370    {
371        if(!sConfig.Reload())
372        {
373            sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str());
374            return;
375        }
376        //TODO Check if config is outdated
377    }
378
379    ///- Read the player limit and the Message of the day from the config file
380    SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT), true );
381    SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) );
382
383    ///- Read all rates from the config file
384    rate_values[RATE_HEALTH]      = sConfig.GetFloatDefault("Rate.Health", 1);
385    if(rate_values[RATE_HEALTH] < 0)
386    {
387        sLog.outError("Rate.Health (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_HEALTH]);
388        rate_values[RATE_HEALTH] = 1;
389    }
390    rate_values[RATE_POWER_MANA]  = sConfig.GetFloatDefault("Rate.Mana", 1);
391    if(rate_values[RATE_POWER_MANA] < 0)
392    {
393        sLog.outError("Rate.Mana (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_MANA]);
394        rate_values[RATE_POWER_MANA] = 1;
395    }
396    rate_values[RATE_POWER_RAGE_INCOME] = sConfig.GetFloatDefault("Rate.Rage.Income", 1);
397    rate_values[RATE_POWER_RAGE_LOSS]   = sConfig.GetFloatDefault("Rate.Rage.Loss", 1);
398    if(rate_values[RATE_POWER_RAGE_LOSS] < 0)
399    {
400        sLog.outError("Rate.Rage.Loss (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_POWER_RAGE_LOSS]);
401        rate_values[RATE_POWER_RAGE_LOSS] = 1;
402    }
403    rate_values[RATE_POWER_FOCUS] = sConfig.GetFloatDefault("Rate.Focus", 1.0f);
404    rate_values[RATE_LOYALTY]     = sConfig.GetFloatDefault("Rate.Loyalty", 1.0f);
405    rate_values[RATE_SKILL_DISCOVERY] = sConfig.GetFloatDefault("Rate.Skill.Discovery", 1.0f);
406    rate_values[RATE_DROP_ITEM_POOR]       = sConfig.GetFloatDefault("Rate.Drop.Item.Poor", 1.0f);
407    rate_values[RATE_DROP_ITEM_NORMAL]     = sConfig.GetFloatDefault("Rate.Drop.Item.Normal", 1.0f);
408    rate_values[RATE_DROP_ITEM_UNCOMMON]   = sConfig.GetFloatDefault("Rate.Drop.Item.Uncommon", 1.0f);
409    rate_values[RATE_DROP_ITEM_RARE]       = sConfig.GetFloatDefault("Rate.Drop.Item.Rare", 1.0f);
410    rate_values[RATE_DROP_ITEM_EPIC]       = sConfig.GetFloatDefault("Rate.Drop.Item.Epic", 1.0f);
411    rate_values[RATE_DROP_ITEM_LEGENDARY]  = sConfig.GetFloatDefault("Rate.Drop.Item.Legendary", 1.0f);
412    rate_values[RATE_DROP_ITEM_ARTIFACT]   = sConfig.GetFloatDefault("Rate.Drop.Item.Artifact", 1.0f);
413    rate_values[RATE_DROP_ITEM_REFERENCED] = sConfig.GetFloatDefault("Rate.Drop.Item.Referenced", 1.0f);
414    rate_values[RATE_DROP_MONEY]  = sConfig.GetFloatDefault("Rate.Drop.Money", 1.0f);
415    rate_values[RATE_XP_KILL]     = sConfig.GetFloatDefault("Rate.XP.Kill", 1.0f);
416    rate_values[RATE_XP_QUEST]    = sConfig.GetFloatDefault("Rate.XP.Quest", 1.0f);
417    rate_values[RATE_XP_EXPLORE]  = sConfig.GetFloatDefault("Rate.XP.Explore", 1.0f);
418    rate_values[RATE_XP_PAST_70]  = sConfig.GetFloatDefault("Rate.XP.PastLevel70", 1.0f);
419    rate_values[RATE_REPUTATION_GAIN]  = sConfig.GetFloatDefault("Rate.Reputation.Gain", 1.0f);
420    rate_values[RATE_CREATURE_NORMAL_DAMAGE]          = sConfig.GetFloatDefault("Rate.Creature.Normal.Damage", 1.0f);
421    rate_values[RATE_CREATURE_ELITE_ELITE_DAMAGE]     = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.Damage", 1.0f);
422    rate_values[RATE_CREATURE_ELITE_RAREELITE_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
423    rate_values[RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f);
424    rate_values[RATE_CREATURE_ELITE_RARE_DAMAGE]      = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.Damage", 1.0f);
425    rate_values[RATE_CREATURE_NORMAL_HP]          = sConfig.GetFloatDefault("Rate.Creature.Normal.HP", 1.0f);
426    rate_values[RATE_CREATURE_ELITE_ELITE_HP]     = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.HP", 1.0f);
427    rate_values[RATE_CREATURE_ELITE_RAREELITE_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.HP", 1.0f);
428    rate_values[RATE_CREATURE_ELITE_WORLDBOSS_HP] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.HP", 1.0f);
429    rate_values[RATE_CREATURE_ELITE_RARE_HP]      = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.HP", 1.0f);
430    rate_values[RATE_CREATURE_NORMAL_SPELLDAMAGE]          = sConfig.GetFloatDefault("Rate.Creature.Normal.SpellDamage", 1.0f);
431    rate_values[RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE]     = sConfig.GetFloatDefault("Rate.Creature.Elite.Elite.SpellDamage", 1.0f);
432    rate_values[RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f);
433    rate_values[RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE] = sConfig.GetFloatDefault("Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f);
434    rate_values[RATE_CREATURE_ELITE_RARE_SPELLDAMAGE]      = sConfig.GetFloatDefault("Rate.Creature.Elite.RARE.SpellDamage", 1.0f);
435    rate_values[RATE_CREATURE_AGGRO]  = sConfig.GetFloatDefault("Rate.Creature.Aggro", 1.0f);
436    rate_values[RATE_REST_INGAME]                    = sConfig.GetFloatDefault("Rate.Rest.InGame", 1.0f);
437    rate_values[RATE_REST_OFFLINE_IN_TAVERN_OR_CITY] = sConfig.GetFloatDefault("Rate.Rest.Offline.InTavernOrCity", 1.0f);
438    rate_values[RATE_REST_OFFLINE_IN_WILDERNESS]     = sConfig.GetFloatDefault("Rate.Rest.Offline.InWilderness", 1.0f);
439    rate_values[RATE_DAMAGE_FALL]  = sConfig.GetFloatDefault("Rate.Damage.Fall", 1.0f);
440    rate_values[RATE_AUCTION_TIME]  = sConfig.GetFloatDefault("Rate.Auction.Time", 1.0f);
441    rate_values[RATE_AUCTION_DEPOSIT] = sConfig.GetFloatDefault("Rate.Auction.Deposit", 1.0f);
442    rate_values[RATE_AUCTION_CUT] = sConfig.GetFloatDefault("Rate.Auction.Cut", 1.0f);
443    rate_values[RATE_HONOR] = sConfig.GetFloatDefault("Rate.Honor",1.0f);
444    rate_values[RATE_MINING_AMOUNT] = sConfig.GetFloatDefault("Rate.Mining.Amount",1.0f);
445    rate_values[RATE_MINING_NEXT]   = sConfig.GetFloatDefault("Rate.Mining.Next",1.0f);
446    rate_values[RATE_INSTANCE_RESET_TIME] = sConfig.GetFloatDefault("Rate.InstanceResetTime",1.0f);
447    rate_values[RATE_TALENT] = sConfig.GetFloatDefault("Rate.Talent",1.0f);
448    if(rate_values[RATE_TALENT] < 0.0f)
449    {
450        sLog.outError("Rate.Talent (%f) mustbe > 0. Using 1 instead.",rate_values[RATE_TALENT]);
451        rate_values[RATE_TALENT] = 1.0f;
452    }
453    rate_values[RATE_CORPSE_DECAY_LOOTED] = sConfig.GetFloatDefault("Rate.Corpse.Decay.Looted",0.1f);
454
455    rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = sConfig.GetFloatDefault("TargetPosRecalculateRange",1.5f);
456    if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] < CONTACT_DISTANCE)
457    {
458        sLog.outError("TargetPosRecalculateRange (%f) must be >= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],CONTACT_DISTANCE,CONTACT_DISTANCE);
459        rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = CONTACT_DISTANCE;
460    }
461    else if(rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] > ATTACK_DISTANCE)
462    {
463        sLog.outError("TargetPosRecalculateRange (%f) must be <= %f. Using %f instead.",rate_values[RATE_TARGET_POS_RECALCULATION_RANGE],ATTACK_DISTANCE,ATTACK_DISTANCE);
464        rate_values[RATE_TARGET_POS_RECALCULATION_RANGE] = ATTACK_DISTANCE;
465    }
466
467    rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f);
468    if(rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f)
469    {
470        sLog.outError("DurabilityLossChance.Damage (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_DAMAGE]);
471        rate_values[RATE_DURABILITY_LOSS_DAMAGE] = 0.0f;
472    }
473    rate_values[RATE_DURABILITY_LOSS_ABSORB] = sConfig.GetFloatDefault("DurabilityLossChance.Absorb",0.5f);
474    if(rate_values[RATE_DURABILITY_LOSS_ABSORB] < 0.0f)
475    {
476        sLog.outError("DurabilityLossChance.Absorb (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ABSORB]);
477        rate_values[RATE_DURABILITY_LOSS_ABSORB] = 0.0f;
478    }
479    rate_values[RATE_DURABILITY_LOSS_PARRY] = sConfig.GetFloatDefault("DurabilityLossChance.Parry",0.05f);
480    if(rate_values[RATE_DURABILITY_LOSS_PARRY] < 0.0f)
481    {
482        sLog.outError("DurabilityLossChance.Parry (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_PARRY]);
483        rate_values[RATE_DURABILITY_LOSS_PARRY] = 0.0f;
484    }
485    rate_values[RATE_DURABILITY_LOSS_BLOCK] = sConfig.GetFloatDefault("DurabilityLossChance.Block",0.05f);
486    if(rate_values[RATE_DURABILITY_LOSS_BLOCK] < 0.0f)
487    {
488        sLog.outError("DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]);
489        rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f;
490    }
491
492    ///- Read other configuration items from the config file
493
494    m_configs[CONFIG_COMPRESSION] = sConfig.GetIntDefault("Compression", 1);
495    if(m_configs[CONFIG_COMPRESSION] < 1 || m_configs[CONFIG_COMPRESSION] > 9)
496    {
497        sLog.outError("Compression level (%i) must be in range 1..9. Using default compression level (1).",m_configs[CONFIG_COMPRESSION]);
498        m_configs[CONFIG_COMPRESSION] = 1;
499    }
500    m_configs[CONFIG_ADDON_CHANNEL] = sConfig.GetBoolDefault("AddonChannel", true);
501    m_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true);
502    m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 900000);
503
504    m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 300000);
505    if(m_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY)
506    {
507        sLog.outError("GridCleanUpDelay (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_GRIDCLEAN],MIN_GRID_DELAY);
508        m_configs[CONFIG_INTERVAL_GRIDCLEAN] = MIN_GRID_DELAY;
509    }
510    if(reload)
511        MapManager::Instance().SetGridCleanUpDelay(m_configs[CONFIG_INTERVAL_GRIDCLEAN]);
512
513    m_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfig.GetIntDefault("MapUpdateInterval", 100);
514    if(m_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY)
515    {
516        sLog.outError("MapUpdateInterval (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_MAPUPDATE],MIN_MAP_UPDATE_DELAY);
517        m_configs[CONFIG_INTERVAL_MAPUPDATE] = MIN_MAP_UPDATE_DELAY;
518    }
519    if(reload)
520        MapManager::Instance().SetMapUpdateInterval(m_configs[CONFIG_INTERVAL_MAPUPDATE]);
521
522    m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 600000);
523
524    if(reload)
525    {
526        uint32 val = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT);
527        if(val!=m_configs[CONFIG_PORT_WORLD])
528            sLog.outError("WorldServerPort option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[CONFIG_PORT_WORLD]);
529    }
530    else
531        m_configs[CONFIG_PORT_WORLD] = sConfig.GetIntDefault("WorldServerPort", DEFAULT_WORLDSERVER_PORT);
532
533    if(reload)
534    {
535        uint32 val = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
536        if(val!=m_configs[CONFIG_SOCKET_SELECTTIME])
537            sLog.outError("SocketSelectTime option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[DEFAULT_SOCKET_SELECT_TIME]);
538    }
539    else
540        m_configs[CONFIG_SOCKET_SELECTTIME] = sConfig.GetIntDefault("SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
541
542
543    m_configs[CONFIG_GROUP_XP_DISTANCE] = sConfig.GetIntDefault("MaxGroupXPDistance", 74);
544    /// \todo Add MonsterSight and GuarderSight (with meaning) in Trinityd.conf or put them as define
545    m_configs[CONFIG_SIGHT_MONSTER] = sConfig.GetIntDefault("MonsterSight", 50);
546    m_configs[CONFIG_SIGHT_GUARDER] = sConfig.GetIntDefault("GuarderSight", 50);
547
548    if(reload)
549    {
550        uint32 val = sConfig.GetIntDefault("GameType", 0);
551        if(val!=m_configs[CONFIG_GAME_TYPE])
552            sLog.outError("GameType option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[CONFIG_GAME_TYPE]);
553    }
554    else
555        m_configs[CONFIG_GAME_TYPE] = sConfig.GetIntDefault("GameType", 0);
556
557    if(reload)
558    {
559        uint32 val = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT);
560        if(val!=m_configs[CONFIG_REALM_ZONE])
561            sLog.outError("RealmZone option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[CONFIG_REALM_ZONE]);
562    }
563    else
564        m_configs[CONFIG_REALM_ZONE] = sConfig.GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT);
565
566    m_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfig.GetBoolDefault("AllowTwoSide.Accounts", false);
567    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT]    = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Chat",false);
568    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Channel",false);
569    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP]   = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Group",false);
570    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD]   = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Guild",false);
571    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION]   = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Auction",false);
572    m_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL]    = sConfig.GetBoolDefault("AllowTwoSide.Interaction.Mail",false);
573    m_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfig.GetBoolDefault("AllowTwoSide.WhoList", false);
574    m_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfig.GetBoolDefault("AllowTwoSide.AddFriend", false);
575    m_configs[CONFIG_STRICT_PLAYER_NAMES]  = sConfig.GetIntDefault("StrictPlayerNames",  0);
576    m_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfig.GetIntDefault("StrictCharterNames", 0);
577    m_configs[CONFIG_STRICT_PET_NAMES]     = sConfig.GetIntDefault("StrictPetNames",     0);
578
579    m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0);
580
581    m_configs[CONFIG_MAX_WHO] = sConfig.GetIntDefault("MaxWhoListReturns", 49);
582
583    m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);
584    if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10)
585    {
586        sLog.outError("CharactersPerRealm (%i) must be in range 1..10. Set to 10.",m_configs[CONFIG_CHARACTERS_PER_REALM]);
587        m_configs[CONFIG_CHARACTERS_PER_REALM] = 10;
588    }
589
590    // must be after CONFIG_CHARACTERS_PER_REALM
591    m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = sConfig.GetIntDefault("CharactersPerAccount", 50);
592    if(m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] < m_configs[CONFIG_CHARACTERS_PER_REALM])
593    {
594        sLog.outError("CharactersPerAccount (%i) can't be less than CharactersPerRealm (%i).",m_configs[CONFIG_CHARACTERS_PER_ACCOUNT],m_configs[CONFIG_CHARACTERS_PER_REALM]);
595        m_configs[CONFIG_CHARACTERS_PER_ACCOUNT] = m_configs[CONFIG_CHARACTERS_PER_REALM];
596    }
597
598    m_configs[CONFIG_SKIP_CINEMATICS] = sConfig.GetIntDefault("SkipCinematics", 0);
599    if(m_configs[CONFIG_SKIP_CINEMATICS] < 0 || m_configs[CONFIG_SKIP_CINEMATICS] > 2)
600    {
601        sLog.outError("SkipCinematics (%i) must be in range 0..2. Set to 0.",m_configs[CONFIG_SKIP_CINEMATICS]);
602        m_configs[CONFIG_SKIP_CINEMATICS] = 0;
603    }
604
605
606    if(reload)
607    {
608        uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 60);
609        if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL])
610            sLog.outError("MaxPlayerLevel option can't be changed at config reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]);
611    }
612    else
613        m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 60);
614    if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > 255)
615    {
616        sLog.outError("MaxPlayerLevel (%i) must be in range 1..255. Set to 255.",m_configs[CONFIG_MAX_PLAYER_LEVEL]);
617        m_configs[CONFIG_MAX_PLAYER_LEVEL] = 255;
618    }
619
620    m_configs[CONFIG_START_PLAYER_LEVEL] = sConfig.GetIntDefault("StartPlayerLevel", 1);
621    if(m_configs[CONFIG_START_PLAYER_LEVEL] < 1)
622    {
623        sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to 1.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]);
624        m_configs[CONFIG_START_PLAYER_LEVEL] = 1;
625    }
626    else if(m_configs[CONFIG_START_PLAYER_LEVEL] > m_configs[CONFIG_MAX_PLAYER_LEVEL])
627    {
628        sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to %u.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]);
629        m_configs[CONFIG_START_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL];
630    }
631    m_configs[CONFIG_MAX_HONOR_POINTS] = sConfig.GetIntDefault("MaxHonorPoints", 75000);
632    m_configs[CONFIG_MAX_ARENA_POINTS] = sConfig.GetIntDefault("MaxArenaPoints", 5000);
633
634    m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false);
635    m_configs[CONFIG_INSTANCE_IGNORE_RAID]  = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
636
637    m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER]              = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
638
639    m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
640    m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR]  = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
641    m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000);
642
643    m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2);
644    m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9);
645    if(m_configs[CONFIG_MIN_PETITION_SIGNS] > 9)
646    {
647        sLog.outError("MinPetitionSigns (%i) must be in range 0..9. Set to 9.",m_configs[CONFIG_MIN_PETITION_SIGNS]);
648        m_configs[CONFIG_MIN_PETITION_SIGNS] = 9;
649    }
650
651    m_configs[CONFIG_GM_LOGIN_STATE]       = sConfig.GetIntDefault("GM.LoginState",2);
652    m_configs[CONFIG_GM_ACCEPT_TICKETS]    = sConfig.GetIntDefault("GM.AcceptTickets",2);
653    m_configs[CONFIG_GM_CHAT]              = sConfig.GetIntDefault("GM.Chat",2);
654    m_configs[CONFIG_GM_WISPERING_TO]      = sConfig.GetIntDefault("GM.WhisperingTo",2);
655
656    m_configs[CONFIG_GM_IN_GM_LIST]        = sConfig.GetBoolDefault("GM.InGMList",false);
657    m_configs[CONFIG_GM_IN_WHO_LIST]       = sConfig.GetBoolDefault("GM.InWhoList",false);
658    m_configs[CONFIG_GM_LOG_TRADE]         = sConfig.GetBoolDefault("GM.LogTrade", false);
659
660    m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0);
661
662    m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR);
663
664    m_configs[CONFIG_UPTIME_UPDATE] = sConfig.GetIntDefault("UpdateUptimeInterval", 10);
665    if(m_configs[CONFIG_UPTIME_UPDATE]<=0)
666    {
667        sLog.outError("UpdateUptimeInterval (%i) must be > 0, set to default 10.",m_configs[CONFIG_UPTIME_UPDATE]);
668        m_configs[CONFIG_UPTIME_UPDATE] = 10;
669    }
670    if(reload)
671    {
672        m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
673        m_timers[WUPDATE_UPTIME].Reset();
674    }
675
676    m_configs[CONFIG_SKILL_CHANCE_ORANGE] = sConfig.GetIntDefault("SkillChance.Orange",100);
677    m_configs[CONFIG_SKILL_CHANCE_YELLOW] = sConfig.GetIntDefault("SkillChance.Yellow",75);
678    m_configs[CONFIG_SKILL_CHANCE_GREEN]  = sConfig.GetIntDefault("SkillChance.Green",25);
679    m_configs[CONFIG_SKILL_CHANCE_GREY]   = sConfig.GetIntDefault("SkillChance.Grey",0);
680
681    m_configs[CONFIG_SKILL_CHANCE_MINING_STEPS]  = sConfig.GetIntDefault("SkillChance.MiningSteps",75);
682    m_configs[CONFIG_SKILL_CHANCE_SKINNING_STEPS]   = sConfig.GetIntDefault("SkillChance.SkinningSteps",75);
683
684    m_configs[CONFIG_SKILL_PROSPECTING] = sConfig.GetBoolDefault("SkillChance.Prospecting",false);
685
686    m_configs[CONFIG_SKILL_GAIN_CRAFTING]  = sConfig.GetIntDefault("SkillGain.Crafting", 1);
687    if(m_configs[CONFIG_SKILL_GAIN_CRAFTING] < 0)
688    {
689        sLog.outError("SkillGain.Crafting (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_CRAFTING]);
690        m_configs[CONFIG_SKILL_GAIN_CRAFTING] = 1;
691    }
692
693    m_configs[CONFIG_SKILL_GAIN_DEFENSE]  = sConfig.GetIntDefault("SkillGain.Defense", 1);
694    if(m_configs[CONFIG_SKILL_GAIN_DEFENSE] < 0)
695    {
696        sLog.outError("SkillGain.Defense (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_DEFENSE]);
697        m_configs[CONFIG_SKILL_GAIN_DEFENSE] = 1;
698    }
699
700    m_configs[CONFIG_SKILL_GAIN_GATHERING]  = sConfig.GetIntDefault("SkillGain.Gathering", 1);
701    if(m_configs[CONFIG_SKILL_GAIN_GATHERING] < 0)
702    {
703        sLog.outError("SkillGain.Gathering (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_GATHERING]);
704        m_configs[CONFIG_SKILL_GAIN_GATHERING] = 1;
705    }
706
707    m_configs[CONFIG_SKILL_GAIN_WEAPON]  = sConfig.GetIntDefault("SkillGain.Weapon", 1);
708    if(m_configs[CONFIG_SKILL_GAIN_WEAPON] < 0)
709    {
710        sLog.outError("SkillGain.Weapon (%i) can't be negative. Set to 1.",m_configs[CONFIG_SKILL_GAIN_WEAPON]);
711        m_configs[CONFIG_SKILL_GAIN_WEAPON] = 1;
712    }
713
714    m_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfig.GetIntDefault("MaxOverspeedPings",2);
715    if(m_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2)
716    {
717        sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check. Set to 2.",m_configs[CONFIG_MAX_OVERSPEED_PINGS]);
718        m_configs[CONFIG_MAX_OVERSPEED_PINGS] = 2;
719    }
720
721    m_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY] = sConfig.GetBoolDefault("SaveRespawnTimeImmediately",true);
722    m_configs[CONFIG_WEATHER] = sConfig.GetBoolDefault("ActivateWeather",true);
723
724    if(reload)
725    {
726        uint32 val = sConfig.GetIntDefault("Expansion",1);
727        if(val!=m_configs[CONFIG_EXPANSION])
728            sLog.outError("Expansion option can't be changed at Trinityd.conf reload, using current value (%u).",m_configs[CONFIG_EXPANSION]);
729    }
730    else
731        m_configs[CONFIG_EXPANSION] = sConfig.GetIntDefault("Expansion",1);
732
733    m_configs[CONFIG_CHATFLOOD_MESSAGE_COUNT] = sConfig.GetIntDefault("ChatFlood.MessageCount",10);
734    m_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfig.GetIntDefault("ChatFlood.MessageDelay",1);
735    m_configs[CONFIG_CHATFLOOD_MUTE_TIME]     = sConfig.GetIntDefault("ChatFlood.MuteTime",10);
736
737    m_configs[CONFIG_EVENT_ANNOUNCE] = sConfig.GetIntDefault("Event.Announce",0);
738
739    m_configs[CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistenceRadius",10);
740
741    m_configs[CONFIG_WORLD_BOSS_LEVEL_DIFF] = sConfig.GetIntDefault("WorldBossLevelDiff",3);
742
743    // note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level (255)
744    m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.LowLevelHideDiff",4);
745    if(m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] > 255)
746        m_configs[CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF] = 255;
747    m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = sConfig.GetIntDefault("Quests.HighLevelHideDiff",7);
748    if(m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] > 255)
749        m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = 255;
750
751    m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true);
752    m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false);
753
754    m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
755    m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false);
756
757    m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60);
758    m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300);
759    m_configs[CONFIG_CORPSE_DECAY_ELITE] = sConfig.GetIntDefault("Corpse.Decay.ELITE", 300);
760    m_configs[CONFIG_CORPSE_DECAY_RAREELITE] = sConfig.GetIntDefault("Corpse.Decay.RAREELITE", 300);
761    m_configs[CONFIG_CORPSE_DECAY_WORLDBOSS] = sConfig.GetIntDefault("Corpse.Decay.WORLDBOSS", 3600);
762
763    m_configs[CONFIG_DEATH_SICKNESS_LEVEL] = sConfig.GetIntDefault("Death.SicknessLevel", 11);
764    m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvP", true);
765    m_configs[CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE] = sConfig.GetBoolDefault("Death.CorpseReclaimDelay.PvE", true);
766
767    m_configs[CONFIG_THREAT_RADIUS] = sConfig.GetIntDefault("ThreatRadius", 100);
768
769    // always use declined names in the Russian client
770    m_configs[CONFIG_DECLINED_NAMES_USED] = 
771        (m_configs[CONFIG_REALM_ZONE] == REALM_ZONE_RUSSIAN) ? true : sConfig.GetBoolDefault("DeclinedNames", false);
772
773    m_configs[CONFIG_LISTEN_RANGE_SAY]       = sConfig.GetIntDefault("ListenRange.Say", 25);
774    m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25);
775    m_configs[CONFIG_LISTEN_RANGE_YELL]      = sConfig.GetIntDefault("ListenRange.Yell", 300);
776
777    m_configs[CONFIG_PLAYER_START_GOLD] = (uint32)(sConfig.GetFloatDefault("PlayerStart.Gold", 0.0f) * 10000.0f);
778
779    if(m_configs[CONFIG_PLAYER_START_GOLD] > MAX_MONEY_AMOUNT)
780        m_configs[CONFIG_PLAYER_START_GOLD] = MAX_MONEY_AMOUNT;
781
782    m_configs[CONFIG_PLAYER_START_HONOR] = sConfig.GetIntDefault("PlayerStart.HonorPoints", 0);
783    if(m_configs[CONFIG_PLAYER_START_HONOR] < 0)
784        m_configs[CONFIG_PLAYER_START_HONOR] = 0;
785
786    m_configs[CONFIG_PLAYER_START_ARENAPTS] = sConfig.GetIntDefault("PlayerStart.ArenaPoints", 0);
787    if(m_configs[CONFIG_PLAYER_START_ARENAPTS] < 0)
788        m_configs[CONFIG_PLAYER_START_ARENAPTS] = 0;
789
790    m_configs[CONFIG_GM_START_LEVEL] = sConfig.GetIntDefault("GamemasterStartLevel", 1);
791    if(m_configs[CONFIG_GM_START_LEVEL] < 1)
792        m_configs[CONFIG_GM_START_LEVEL] = 1;
793
794    m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetBoolDefault("PlayerInstantLogout", false);
795    m_configs[CONFIG_BG_START_MUSIC] = sConfig.GetBoolDefault("MusicInBattleground", false);
796    m_configs[CONFIG_START_ALL_SPELLS] = sConfig.GetBoolDefault("PlayerStart.AllSpells", false);
797    m_configs[CONFIG_HONOR_AFTER_DUEL] = sConfig.GetIntDefault("HonorPointsAfterDuel", 0);
798    if(m_configs[CONFIG_HONOR_AFTER_DUEL] < 0)
799        m_configs[CONFIG_HONOR_AFTER_DUEL]= 0;
800    m_configs[CONFIG_START_ALL_EXPLORED] = sConfig.GetBoolDefault("PlayerStart.MapsExplored", false);
801    m_configs[CONFIG_DISABLE_BREATHING] = sConfig.GetBoolDefault("DisableWaterBreath", false);
802    m_configs[CONFIG_START_ALL_REP] = sConfig.GetBoolDefault("PlayerStart.AllReputation", false);
803    m_configs[CONFIG_ALWAYS_MAXSKILL] = sConfig.GetBoolDefault("AlwaysMaxWeaponSkill", false);
804    m_configs[CONFIG_START_ALL_TAXI] = sConfig.GetBoolDefault("PlayerStart.AllFlightPaths", false);
805    m_configs[CONFIG_PVP_TOKEN_ENABLE] = sConfig.GetBoolDefault("PvPToken.Enable", false);
806    m_configs[CONFIG_PVP_TOKEN_MAP_TYPE] = sConfig.GetIntDefault("PvPToken.MapAllowType", 4);
807    m_configs[CONFIG_PVP_TOKEN_ID] = sConfig.GetIntDefault("PvPToken.ItemID", 29434);
808    m_configs[CONFIG_PVP_TOKEN_COUNT] = sConfig.GetIntDefault("PvPToken.ItemCount", 1);
809    if(m_configs[CONFIG_PVP_TOKEN_COUNT] < 1)
810        m_configs[CONFIG_PVP_TOKEN_COUNT] = 1;
811    m_configs[CONFIG_NO_RESET_TALENT_COST] = sConfig.GetBoolDefault("NoResetTalentsCost", false);
812
813    m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);
814    m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);
815    m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
816    m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
817
818    m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
819
820    m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
821    if(m_VisibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE)
822    {
823        sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE);
824        m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
825    }
826    m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10);
827    if(m_VisibleObjectGreyDistance >  MAX_VISIBILITY_DISTANCE)
828    {
829        sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE);
830        m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
831    }
832
833    m_MaxVisibleDistanceForCreature      = sConfig.GetFloatDefault("Visibility.Distance.Creature",     DEFAULT_VISIBILITY_DISTANCE);
834    if(m_MaxVisibleDistanceForCreature < 45*sWorld.getRate(RATE_CREATURE_AGGRO))
835    {
836        sLog.outError("Visibility.Distance.Creature can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO));
837        m_MaxVisibleDistanceForCreature = 45*sWorld.getRate(RATE_CREATURE_AGGRO);
838    }
839    else if(m_MaxVisibleDistanceForCreature + m_VisibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE)
840    {
841        sLog.outError("Visibility. Distance .Creature can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
842        m_MaxVisibleDistanceForCreature = MAX_VISIBILITY_DISTANCE-m_VisibleUnitGreyDistance;
843    }
844    m_MaxVisibleDistanceForPlayer        = sConfig.GetFloatDefault("Visibility.Distance.Player",       DEFAULT_VISIBILITY_DISTANCE);
845    if(m_MaxVisibleDistanceForPlayer < 45*sWorld.getRate(RATE_CREATURE_AGGRO))
846    {
847        sLog.outError("Visibility.Distance.Player can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO));
848        m_MaxVisibleDistanceForPlayer = 45*sWorld.getRate(RATE_CREATURE_AGGRO);
849    }
850    else if(m_MaxVisibleDistanceForPlayer + m_VisibleUnitGreyDistance >  MAX_VISIBILITY_DISTANCE)
851    {
852        sLog.outError("Visibility.Distance.Player can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
853        m_MaxVisibleDistanceForPlayer = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
854    }
855    m_MaxVisibleDistanceForObject    = sConfig.GetFloatDefault("Visibility.Distance.Gameobject",   DEFAULT_VISIBILITY_DISTANCE);
856    if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE)
857    {
858        sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
859        m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE;
860    }
861    else if(m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance >  MAX_VISIBILITY_DISTANCE)
862    {
863        sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
864        m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
865    }
866    m_MaxVisibleDistanceInFlight    = sConfig.GetFloatDefault("Visibility.Distance.InFlight",      DEFAULT_VISIBILITY_DISTANCE);
867    if(m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
868    {
869        sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
870        m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
871    }
872
873    ///- Read the "Data" directory from the config file
874    std::string dataPath = sConfig.GetStringDefault("DataDir","./");
875    if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' )
876        dataPath.append("/");
877
878    if(reload)
879    {
880        if(dataPath!=m_dataPath)
881            sLog.outError("DataDir option can't be changed at Trinityd.conf reload, using current value (%s).",m_dataPath.c_str());
882    }
883    else
884    {
885        m_dataPath = dataPath;
886        sLog.outString("Using DataDir %s",m_dataPath.c_str());
887    }
888
889    std::string forbiddenmaps = sConfig.GetStringDefault("ForbiddenMaps", "");
890    char * forbiddenMaps = new char[forbiddenmaps.length() + 1];
891    forbiddenMaps[forbiddenmaps.length()] = 0;
892    strncpy(forbiddenMaps, forbiddenmaps.c_str(), forbiddenmaps.length());
893    const char * delim = ",";
894    char * token = strtok(forbiddenMaps, delim);
895    while(token != NULL)
896    {
897        int32 mapid = strtol(token, NULL, 10);
898        m_forbiddenMapIds.insert(mapid);
899        token = strtok(NULL,delim);
900    }
901    delete[] forbiddenMaps;
902
903    bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
904    bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
905    std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
906    std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", "");
907    VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
908    VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
909    VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str());
910    VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
911    sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight);
912    sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str());
913    sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");
914}
915
916/// Initialize the World
917void World::SetInitialWorldSettings()
918{
919    ///- Initialize the random number generator
920    srand((unsigned int)time(NULL));
921
922    ///- Initialize config settings
923    LoadConfigSettings();
924
925    ///- Init highest guids before any table loading to prevent using not initialized guids in some code.
926    objmgr.SetHighestGuids();
927
928    ///- Check the existence of the map files for all races' startup areas.
929    if(   !MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f)
930        ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
931        ||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
932        ||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f)
933        ||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f)
934        ||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f)
935        ||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f)
936        ||m_configs[CONFIG_EXPANSION] && (
937        !MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
938    {
939        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 Trinityd.conf file.",m_dataPath.c_str(),m_dataPath.c_str());
940        exit(1);
941    }
942
943    ///- Loading strings. Getting no records means core load has to be canceled because no error message can be output.
944    sLog.outString( "" );
945    sLog.outString( "Loading Trinity strings..." );
946    if (!objmgr.LoadTrinityStrings())
947        exit(1);                                            // Error message displayed in function already
948
949    ///- Update the realm entry in the database with the realm type from the config file
950    //No SQL injection as values are treated as integers
951
952    // not send custom type REALM_FFA_PVP to realm list
953    uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE);
954    uint32 realm_zone = getConfig(CONFIG_REALM_ZONE);
955    loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
956
957    ///- Remove the bones after a restart
958    CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'");
959
960    ///- Load the DBC files
961    sLog.outString("Initialize data stores...");
962    LoadDBCStores(m_dataPath);
963    DetectDBCLang();
964
965    sLog.outString( "Loading InstanceTemplate" );
966    objmgr.LoadInstanceTemplate();
967
968    sLog.outString( "Loading SkillLineAbilityMultiMap Data..." );
969    spellmgr.LoadSkillLineAbilityMap();
970
971    ///- Clean up and pack instances
972    sLog.outString( "Cleaning up instances..." );
973    sInstanceSaveManager.CleanupInstances();                              // must be called before `creature_respawn`/`gameobject_respawn` tables
974
975    sLog.outString( "Packing instances..." );
976    sInstanceSaveManager.PackInstances();
977
978    sLog.outString( "Loading Localization strings..." );
979    objmgr.LoadCreatureLocales();
980    objmgr.LoadGameObjectLocales();
981    objmgr.LoadItemLocales();
982    objmgr.LoadQuestLocales();
983    objmgr.LoadNpcTextLocales();
984    objmgr.LoadPageTextLocales();
985    objmgr.SetDBCLocaleIndex(GetDefaultDbcLocale());        // Get once for all the locale index of DBC language (console/broadcasts)
986
987    sLog.outString( "Loading Page Texts..." );
988    objmgr.LoadPageTexts();
989
990    sLog.outString( "Loading Player info in cache..." );
991    objmgr.LoadPlayerInfoInCache();
992
993    sLog.outString( "Loading Game Object Templates..." );   // must be after LoadPageTexts
994    objmgr.LoadGameobjectInfo();
995
996    sLog.outString( "Loading Spell Chain Data..." );
997    spellmgr.LoadSpellChains();
998
999    sLog.outString( "Loading Spell Elixir types..." );
1000    spellmgr.LoadSpellElixirs();
1001
1002    sLog.outString( "Loading Spell Learn Skills..." );
1003    spellmgr.LoadSpellLearnSkills();                        // must be after LoadSpellChains
1004
1005    sLog.outString( "Loading Spell Learn Spells..." );
1006    spellmgr.LoadSpellLearnSpells();
1007
1008    sLog.outString( "Loading Spell Proc Event conditions..." );
1009    spellmgr.LoadSpellProcEvents();
1010
1011    sLog.outString( "Loading Aggro Spells Definitions...");
1012    spellmgr.LoadSpellThreats();
1013
1014    sLog.outString( "Loading NPC Texts..." );
1015    objmgr.LoadGossipText();
1016
1017    sLog.outString( "Loading Item Random Enchantments Table..." );
1018    LoadRandomEnchantmentsTable();
1019
1020    sLog.outString( "Loading Items..." );                   // must be after LoadRandomEnchantmentsTable and LoadPageTexts
1021    objmgr.LoadItemPrototypes();
1022
1023    sLog.outString( "Loading Item Texts..." );
1024    objmgr.LoadItemTexts();
1025
1026    sLog.outString( "Loading Creature Model Based Info Data..." );
1027    objmgr.LoadCreatureModelInfo();
1028
1029    sLog.outString( "Loading Equipment templates...");
1030    objmgr.LoadEquipmentTemplates();
1031
1032    sLog.outString( "Loading Creature templates..." );
1033    objmgr.LoadCreatureTemplates();
1034
1035    sLog.outString( "Loading SpellsScriptTarget...");
1036    spellmgr.LoadSpellScriptTarget();                       // must be after LoadCreatureTemplates and LoadGameobjectInfo
1037
1038    sLog.outString( "Loading Creature Reputation OnKill Data..." );
1039    objmgr.LoadReputationOnKill();
1040
1041    sLog.outString( "Loading Pet Create Spells..." );
1042    objmgr.LoadPetCreateSpells();
1043
1044    sLog.outString( "Loading Creature Data..." );
1045    objmgr.LoadCreatures();
1046
1047    sLog.outString( "Loading Creature Addon Data..." );
1048    objmgr.LoadCreatureAddons();                            // must be after LoadCreatureTemplates() and LoadCreatures()
1049
1050    sLog.outString( "Loading Creature Respawn Data..." );   // must be after PackInstances()
1051    objmgr.LoadCreatureRespawnTimes();
1052
1053    sLog.outString( "Loading Gameobject Data..." );
1054    objmgr.LoadGameobjects();
1055
1056    sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
1057    objmgr.LoadGameobjectRespawnTimes();
1058
1059    sLog.outString( "Loading Game Event Data...");
1060    gameeventmgr.LoadFromDB();
1061
1062    sLog.outString( "Loading Weather Data..." );
1063    objmgr.LoadWeatherZoneChances();
1064
1065    sLog.outString( "Loading Quests..." );
1066    objmgr.LoadQuests();                                    // must be loaded after DBCs, creature_template, item_template, gameobject tables
1067
1068    sLog.outString( "Loading Quests Relations..." );
1069    objmgr.LoadQuestRelations();                            // must be after quest load
1070
1071    sLog.outString( "Loading AreaTrigger definitions..." );
1072    objmgr.LoadAreaTriggerTeleports();                      // must be after item template load
1073
1074    sLog.outString( "Loading Quest Area Triggers..." );
1075    objmgr.LoadQuestAreaTriggers();                         // must be after LoadQuests
1076
1077    sLog.outString( "Loading Tavern Area Triggers..." );
1078    objmgr.LoadTavernAreaTriggers();
1079   
1080    sLog.outString( "Loading AreaTrigger script names..." );
1081    objmgr.LoadAreaTriggerScripts();
1082
1083
1084    sLog.outString( "Loading Graveyard-zone links...");
1085    objmgr.LoadGraveyardZones();
1086
1087    sLog.outString( "Loading Spell target coordinates..." );
1088    spellmgr.LoadSpellTargetPositions();
1089
1090    sLog.outString( "Loading SpellAffect definitions..." );
1091    spellmgr.LoadSpellAffects();
1092
1093    sLog.outString( "Loading spell pet auras..." );
1094    spellmgr.LoadSpellPetAuras();
1095
1096    sLog.outString( "Loading spell extra attributes...(TODO)" );
1097    spellmgr.LoadSpellExtraAttr();
1098
1099    sLog.outString( "Loading player Create Info & Level Stats..." );
1100    objmgr.LoadPlayerInfo();
1101
1102    sLog.outString( "Loading Exploration BaseXP Data..." );
1103    objmgr.LoadExplorationBaseXP();
1104
1105    sLog.outString( "Loading Pet Name Parts..." );
1106    objmgr.LoadPetNames();
1107
1108    sLog.outString( "Loading the max pet number..." );
1109    objmgr.LoadPetNumber();
1110
1111    sLog.outString( "Loading pet level stats..." );
1112    objmgr.LoadPetLevelInfo();
1113
1114    sLog.outString( "Loading Player Corpses..." );
1115    objmgr.LoadCorpses();
1116
1117    sLog.outString( "Loading Disabled Spells..." );
1118    objmgr.LoadSpellDisabledEntrys();
1119
1120    sLog.outString( "Loading Loot Tables..." );
1121    LoadLootTables();
1122
1123    sLog.outString( "Loading Skill Discovery Table..." );
1124    LoadSkillDiscoveryTable();
1125
1126    sLog.outString( "Loading Skill Extra Item Table..." );
1127    LoadSkillExtraItemTable();
1128
1129    sLog.outString( "Loading Skill Fishing base level requirements..." );
1130    objmgr.LoadFishingBaseSkillLevel();
1131
1132    ///- Load dynamic data tables from the database
1133    sLog.outString( "Loading Auctions..." );
1134    objmgr.LoadAuctionItems();
1135    objmgr.LoadAuctions();
1136
1137    sLog.outString( "Loading Guilds..." );
1138    objmgr.LoadGuilds();
1139
1140    sLog.outString( "Loading ArenaTeams..." );
1141    objmgr.LoadArenaTeams();
1142
1143    sLog.outString( "Loading Groups..." );
1144    objmgr.LoadGroups();
1145
1146    sLog.outString( "Loading ReservedNames..." );
1147    objmgr.LoadReservedPlayersNames();
1148
1149    sLog.outString( "Loading GameObject for quests..." );
1150    objmgr.LoadGameObjectForQuests();
1151
1152    sLog.outString( "Loading BattleMasters..." );
1153    objmgr.LoadBattleMastersEntry();
1154
1155    sLog.outString( "Loading GameTeleports..." );
1156    objmgr.LoadGameTele();
1157
1158    sLog.outString( "Loading Npc Text Id..." );
1159    objmgr.LoadNpcTextId();                                 // must be after load Creature and NpcText
1160
1161    sLog.outString( "Loading vendors..." );
1162    objmgr.LoadVendors();                                   // must be after load CreatureTemplate and ItemTemplate
1163
1164    sLog.outString( "Loading trainers..." );
1165    objmgr.LoadTrainerSpell();                              // must be after load CreatureTemplate
1166
1167    sLog.outString( "Loading Waypoints..." );
1168    WaypointMgr.Load();
1169
1170    ///- Handle outdated emails (delete/return)
1171    sLog.outString( "Returning old mails..." );
1172    objmgr.ReturnOrDeleteOldMails(false);
1173
1174    ///- Load and initialize scripts
1175    sLog.outString( "Loading Scripts..." );
1176    objmgr.LoadQuestStartScripts();                         // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1177    objmgr.LoadQuestEndScripts();                           // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1178    objmgr.LoadSpellScripts();                              // must be after load Creature/Gameobject(Template/Data)
1179    objmgr.LoadGameObjectScripts();                         // must be after load Creature/Gameobject(Template/Data)
1180    objmgr.LoadEventScripts();                              // must be after load Creature/Gameobject(Template/Data)
1181
1182    sLog.outString( "Initializing Scripts..." );
1183    if(!LoadScriptingModule())
1184        exit(1);
1185
1186    ///- Initialize game time and timers
1187    sLog.outString( "DEBUG:: Initialize game time and timers" );
1188    m_gameTime = time(NULL);
1189    m_startTime=m_gameTime;
1190
1191    tm local;
1192    time_t curr;
1193    time(&curr);
1194    local=*(localtime(&curr));                              // dereference and assign
1195    char isoDate[128];
1196    sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
1197        local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
1198
1199    WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', %ld, 0)", isoDate, m_startTime );
1200
1201    m_timers[WUPDATE_OBJECTS].SetInterval(0);
1202    m_timers[WUPDATE_SESSIONS].SetInterval(0);
1203    m_timers[WUPDATE_WEATHERS].SetInterval(1000);
1204    m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000);    //set auction update interval to 1 minute
1205    m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
1206                                                            //Update "uptime" table based on configuration entry in minutes.
1207    m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000);  //erase corpses every 20 minutes
1208
1209    //to set mailtimer to return mails every day between 4 and 5 am
1210    //mailtimer is increased when updating auctions
1211    //one second is 1000 -(tested on win system)
1212    mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
1213                                                            //1440
1214    mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
1215    sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
1216
1217    ///- Initilize static helper structures
1218    AIRegistry::Initialize();
1219    WaypointMovementGenerator<Creature>::Initialize();
1220    Player::InitVisibleBits();
1221
1222    ///- Initialize MapManager
1223    sLog.outString( "Starting Map System" );
1224    MapManager::Instance().Initialize();
1225
1226    ///- Initialize Battlegrounds
1227    sLog.outString( "Starting BattleGround System" );
1228    sBattleGroundMgr.CreateInitialBattleGrounds();
1229    sBattleGroundMgr.InitAutomaticArenaPointDistribution();
1230
1231    ///- Initialize outdoor pvp
1232    sLog.outString( "Starting Outdoor PvP System" );
1233    sOutdoorPvPMgr.InitOutdoorPvP();
1234
1235    //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
1236    sLog.outString( "Loading Transports..." );
1237    MapManager::Instance().LoadTransports();
1238
1239    sLog.outString("Deleting expired bans..." );
1240    loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
1241
1242    sLog.outString("Calculate next daily quest reset time..." );
1243    InitDailyQuestResetTime();
1244
1245    sLog.outString("Starting Game Event system..." );
1246    uint32 nextGameEvent = gameeventmgr.Initialize();
1247    m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);    //depend on next event
1248
1249    sLog.outString( "WORLD: World initialized" );
1250}
1251void World::DetectDBCLang()
1252{
1253    uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255);
1254
1255    if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE)
1256    {
1257        sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE);
1258        m_lang_confid = LOCALE_enUS;
1259    }
1260
1261    ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1);
1262
1263    std::string availableLocalsStr;
1264
1265    int default_locale = MAX_LOCALE;
1266    for (int i = MAX_LOCALE-1; i >= 0; --i)
1267    {
1268        if ( strlen(race->name[i]) > 0)                     // check by race names
1269        {
1270            default_locale = i;
1271            m_availableDbcLocaleMask |= (1 << i);
1272            availableLocalsStr += localeNames[i];
1273            availableLocalsStr += " ";
1274        }
1275    }
1276
1277    if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE &&
1278        (m_availableDbcLocaleMask & (1 << m_lang_confid)) )
1279    {
1280        default_locale = m_lang_confid;
1281    }
1282
1283    if(default_locale >= MAX_LOCALE)
1284    {
1285        sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)");
1286        exit(1);
1287    }
1288
1289    m_defaultDbcLocale = LocaleConstant(default_locale);
1290
1291    sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
1292}
1293
1294/// Update the World !
1295void World::Update(time_t diff)
1296{
1297    ///- Update the different timers
1298    for(int i = 0; i < WUPDATE_COUNT; i++)
1299        if(m_timers[i].GetCurrent()>=0)
1300            m_timers[i].Update(diff);
1301    else m_timers[i].SetCurrent(0);
1302
1303    ///- Update the game time and check for shutdown time
1304    _UpdateGameTime();
1305
1306    /// Handle daily quests reset time
1307    if(m_gameTime > m_NextDailyQuestReset)
1308    {
1309        ResetDailyQuests();
1310        m_NextDailyQuestReset += DAY;
1311    }
1312
1313    /// <ul><li> Handle auctions when the timer has passed
1314    if (m_timers[WUPDATE_AUCTIONS].Passed())
1315    {
1316        m_timers[WUPDATE_AUCTIONS].Reset();
1317
1318        ///- Update mails (return old mails with item, or delete them)
1319        //(tested... works on win)
1320        if (++mail_timer > mail_timer_expires)
1321        {
1322            mail_timer = 0;
1323            objmgr.ReturnOrDeleteOldMails(true);
1324        }
1325
1326        AuctionHouseObject* AuctionMap;
1327        for (int i = 0; i < 3; i++)
1328        {
1329            switch (i)
1330            {
1331                case 0:
1332                    AuctionMap = objmgr.GetAuctionsMap( 6 );//horde
1333                    break;
1334                case 1:
1335                    AuctionMap = objmgr.GetAuctionsMap( 2 );//alliance
1336                    break;
1337                case 2:
1338                    AuctionMap = objmgr.GetAuctionsMap( 7 );//neutral
1339                    break;
1340            }
1341
1342            ///- Handle expired auctions
1343            AuctionHouseObject::AuctionEntryMap::iterator itr,next;
1344            for (itr = AuctionMap->GetAuctionsBegin(); itr != AuctionMap->GetAuctionsEnd();itr = next)
1345            {
1346                next = itr;
1347                ++next;
1348                if (m_gameTime > (itr->second->time))
1349                {
1350                    ///- Either cancel the auction if there was no bidder
1351                    if (itr->second->bidder == 0)
1352                    {
1353                        objmgr.SendAuctionExpiredMail( itr->second );
1354                    }
1355                    ///- Or perform the transaction
1356                    else
1357                    {
1358                        //we should send an "item sold" message if the seller is online
1359                        //we send the item to the winner
1360                        //we send the money to the seller
1361                        objmgr.SendAuctionSuccessfulMail( itr->second );
1362                        objmgr.SendAuctionWonMail( itr->second );
1363                    }
1364
1365                    ///- In any case clear the auction
1366                    //No SQL injection (Id is integer)
1367                    CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",itr->second->Id);
1368                    objmgr.RemoveAItem(itr->second->item_guidlow);
1369                    delete itr->second;
1370                    AuctionMap->RemoveAuction(itr->first);
1371                }
1372            }
1373        }
1374    }
1375
1376    /// <li> Handle session updates when the timer has passed
1377    if (m_timers[WUPDATE_SESSIONS].Passed())
1378    {
1379        m_timers[WUPDATE_SESSIONS].Reset();
1380
1381        UpdateSessions(diff);
1382    }
1383
1384    /// <li> Handle weather updates when the timer has passed
1385    if (m_timers[WUPDATE_WEATHERS].Passed())
1386    {
1387        m_timers[WUPDATE_WEATHERS].Reset();
1388
1389        ///- Send an update signal to Weather objects
1390        WeatherMap::iterator itr, next;
1391        for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next)
1392        {
1393            next = itr;
1394            ++next;
1395
1396            ///- and remove Weather objects for zones with no player
1397                                                            //As interval > WorldTick
1398            if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval()))
1399            {
1400                delete itr->second;
1401                m_weathers.erase(itr);
1402            }
1403        }
1404    }
1405    /// <li> Update uptime table
1406    if (m_timers[WUPDATE_UPTIME].Passed())
1407    {
1408        uint32 tmpDiff = (m_gameTime - m_startTime);
1409        uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount();
1410
1411        m_timers[WUPDATE_UPTIME].Reset();
1412        WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime));
1413    }
1414
1415    /// <li> Handle all other objects
1416    if (m_timers[WUPDATE_OBJECTS].Passed())
1417    {
1418        m_timers[WUPDATE_OBJECTS].Reset();
1419        ///- Update objects when the timer has passed (maps, transport, creatures,...)
1420        MapManager::Instance().Update(diff);                // As interval = 0
1421
1422        ///- Process necessary scripts
1423        if (!m_scriptSchedule.empty())
1424            ScriptsProcess();
1425
1426        sBattleGroundMgr.Update(diff);
1427
1428        sOutdoorPvPMgr.Update(diff);
1429    }
1430
1431    // execute callbacks from sql queries that were queued recently
1432    UpdateResultQueue();
1433
1434    ///- Erase corpses once every 20 minutes
1435    if (m_timers[WUPDATE_CORPSES].Passed())
1436    {
1437        m_timers[WUPDATE_CORPSES].Reset();
1438
1439        CorpsesErase();
1440    }
1441
1442    ///- Process Game events when necessary
1443    if (m_timers[WUPDATE_EVENTS].Passed())
1444    {
1445        m_timers[WUPDATE_EVENTS].Reset();                   // to give time for Update() to be processed
1446        uint32 nextGameEvent = gameeventmgr.Update();
1447        m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
1448        m_timers[WUPDATE_EVENTS].Reset();
1449    }
1450
1451    MapManager::Instance().DoDelayedMovesAndRemoves(); ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
1452
1453    // update the instance reset times
1454    sInstanceSaveManager.Update();
1455
1456    // And last, but not least handle the issued cli commands
1457    ProcessCliCommands();
1458}
1459
1460void World::ForceGameEventUpdate()
1461{
1462    m_timers[WUPDATE_EVENTS].Reset();                   // to give time for Update() to be processed
1463    uint32 nextGameEvent = gameeventmgr.Update();
1464    m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
1465    m_timers[WUPDATE_EVENTS].Reset();
1466}
1467
1468/// Put scripts in the execution queue
1469void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target)
1470{
1471    ///- Find the script map
1472    ScriptMapMap::const_iterator s = scripts.find(id);
1473    if (s == scripts.end())
1474        return;
1475
1476    // prepare static data
1477    uint64 sourceGUID = source->GetGUID();
1478    uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
1479    uint64 ownerGUID  = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
1480
1481    ///- Schedule script execution for all scripts in the script map
1482    ScriptMap const *s2 = &(s->second);
1483    bool immedScript = false;
1484    for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
1485    {
1486        ScriptAction sa;
1487        sa.sourceGUID = sourceGUID;
1488        sa.targetGUID = targetGUID;
1489        sa.ownerGUID  = ownerGUID;
1490
1491        sa.script = &iter->second;
1492        m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + iter->first, sa));
1493        if (iter->first == 0)
1494            immedScript = true;
1495    }
1496    ///- If one of the effects should be immediate, launch the script execution
1497    if (immedScript)
1498        ScriptsProcess();
1499}
1500
1501void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
1502{
1503    // NOTE: script record _must_ exist until command executed
1504
1505    // prepare static data
1506    uint64 sourceGUID = source->GetGUID();
1507    uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
1508    uint64 ownerGUID  = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
1509
1510    ScriptAction sa;
1511    sa.sourceGUID = sourceGUID;
1512    sa.targetGUID = targetGUID;
1513    sa.ownerGUID  = ownerGUID;
1514
1515    sa.script = &script;
1516    m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + delay, sa));
1517
1518    ///- If effects should be immediate, launch the script execution
1519    if(delay == 0)
1520        ScriptsProcess();
1521}
1522
1523/// Process queued scripts
1524void World::ScriptsProcess()
1525{
1526    if (m_scriptSchedule.empty())
1527        return;
1528
1529    ///- Process overdue queued scripts
1530    std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin();
1531                                                            // ok as multimap is a *sorted* associative container
1532    while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime))
1533    {
1534        ScriptAction const& step = iter->second;
1535
1536        Object* source = NULL;
1537
1538        if(step.sourceGUID)
1539        {
1540            switch(GUID_HIPART(step.sourceGUID))
1541            {
1542                case HIGHGUID_ITEM:
1543                    // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM
1544                    {
1545                        Player* player = HashMapHolder<Player>::Find(step.ownerGUID);
1546                        if(player)
1547                            source = player->GetItemByGuid(step.sourceGUID);
1548                        break;
1549                    }
1550                case HIGHGUID_UNIT:
1551                    source = HashMapHolder<Creature>::Find(step.sourceGUID);
1552                    break;
1553                case HIGHGUID_PET:
1554                    source = HashMapHolder<Pet>::Find(step.sourceGUID);
1555                    break;
1556                case HIGHGUID_PLAYER:
1557                    source = HashMapHolder<Player>::Find(step.sourceGUID);
1558                    break;
1559                case HIGHGUID_GAMEOBJECT:
1560                    source = HashMapHolder<GameObject>::Find(step.sourceGUID);
1561                    break;
1562                case HIGHGUID_CORPSE:
1563                    source = HashMapHolder<Corpse>::Find(step.sourceGUID);
1564                    break;
1565                default:
1566                    sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID));
1567                    break;
1568            }
1569        }
1570
1571        Object* target = NULL;
1572
1573        if(step.targetGUID)
1574        {
1575            switch(GUID_HIPART(step.targetGUID))
1576            {
1577                case HIGHGUID_UNIT:
1578                    target = HashMapHolder<Creature>::Find(step.targetGUID);
1579                    break;
1580                case HIGHGUID_PET:
1581                    target = HashMapHolder<Pet>::Find(step.targetGUID);
1582                    break;
1583                case HIGHGUID_PLAYER:                       // empty GUID case also
1584                    target = HashMapHolder<Player>::Find(step.targetGUID);
1585                    break;
1586                case HIGHGUID_GAMEOBJECT:
1587                    target = HashMapHolder<GameObject>::Find(step.targetGUID);
1588                    break;
1589                case HIGHGUID_CORPSE:
1590                    target = HashMapHolder<Corpse>::Find(step.targetGUID);
1591                    break;
1592                default:
1593                    sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID));
1594                    break;
1595            }
1596        }
1597
1598        switch (step.script->command)
1599        {
1600            case SCRIPT_COMMAND_TALK:
1601            {
1602                if(!source)
1603                {
1604                    sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature.");
1605                    break;
1606                }
1607
1608                if(source->GetTypeId()!=TYPEID_UNIT)
1609                {
1610                    sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1611                    break;
1612                }
1613                if(step.script->datalong > 3)
1614                {
1615                    sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong);
1616                    break;
1617                }
1618
1619                uint64 unit_target = target ? target->GetGUID() : 0;
1620
1621                //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text
1622                switch(step.script->datalong)
1623                {
1624                    case 0:                                 // Say
1625                        ((Creature *)source)->Say(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target);
1626                        break;
1627                    case 1:                                 // Whisper
1628                        if(!unit_target)
1629                        {
1630                            sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong);
1631                            break;
1632                        }
1633                        ((Creature *)source)->Whisper(step.script->datatext.c_str(),unit_target);
1634                        break;
1635                    case 2:                                 // Yell
1636                        ((Creature *)source)->Yell(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target);
1637                        break;
1638                    case 3:                                 // Emote text
1639                        ((Creature *)source)->TextEmote(step.script->datatext.c_str(), unit_target);
1640                        break;
1641                    default:
1642                        break;                              // must be already checked at load
1643                }
1644                break;
1645            }
1646
1647            case SCRIPT_COMMAND_EMOTE:
1648                if(!source)
1649                {
1650                    sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature.");
1651                    break;
1652                }
1653
1654                if(source->GetTypeId()!=TYPEID_UNIT)
1655                {
1656                    sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1657                    break;
1658                }
1659
1660                ((Creature *)source)->HandleEmoteCommand(step.script->datalong);
1661                break;
1662            case SCRIPT_COMMAND_FIELD_SET:
1663                if(!source)
1664                {
1665                    sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object.");
1666                    break;
1667                }
1668                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1669                {
1670                    sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
1671                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1672                    break;
1673                }
1674
1675                source->SetUInt32Value(step.script->datalong, step.script->datalong2);
1676                break;
1677            case SCRIPT_COMMAND_MOVE_TO:
1678                if(!source)
1679                {
1680                    sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature.");
1681                    break;
1682                }
1683
1684                if(source->GetTypeId()!=TYPEID_UNIT)
1685                {
1686                    sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1687                    break;
1688                }
1689                ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 );
1690                MapManager::Instance().GetMap(((Unit *)source)->GetMapId(), ((Unit *)source))->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0);
1691                break;
1692            case SCRIPT_COMMAND_FLAG_SET:
1693                if(!source)
1694                {
1695                    sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object.");
1696                    break;
1697                }
1698                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1699                {
1700                    sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
1701                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1702                    break;
1703                }
1704
1705                source->SetFlag(step.script->datalong, step.script->datalong2);
1706                break;
1707            case SCRIPT_COMMAND_FLAG_REMOVE:
1708                if(!source)
1709                {
1710                    sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object.");
1711                    break;
1712                }
1713                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1714                {
1715                    sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).",
1716                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1717                    break;
1718                }
1719
1720                source->RemoveFlag(step.script->datalong, step.script->datalong2);
1721                break;
1722
1723            case SCRIPT_COMMAND_TELEPORT_TO:
1724            {
1725                // accept player in any one from target/source arg
1726                if (!target && !source)
1727                {
1728                    sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object.");
1729                    break;
1730                }
1731
1732                                                            // must be only Player
1733                if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER))
1734                {
1735                    sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
1736                    break;
1737                }
1738
1739                Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source;
1740
1741                pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
1742                break;
1743            }
1744
1745            case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
1746            {
1747                if(!step.script->datalong)                  // creature not specified
1748                {
1749                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature.");
1750                    break;
1751                }
1752
1753                if(!source)
1754                {
1755                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object.");
1756                    break;
1757                }
1758
1759                WorldObject* summoner = dynamic_cast<WorldObject*>(source);
1760
1761                if(!summoner)
1762                {
1763                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
1764                    break;
1765                }
1766
1767                float x = step.script->x;
1768                float y = step.script->y;
1769                float z = step.script->z;
1770                float o = step.script->o;
1771
1772                Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2);
1773                if (!pCreature)
1774                {
1775                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong);
1776                    break;
1777                }
1778
1779                break;
1780            }
1781
1782            case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
1783            {
1784                if(!step.script->datalong)                  // gameobject not specified
1785                {
1786                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject.");
1787                    break;
1788                }
1789
1790                if(!source)
1791                {
1792                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object.");
1793                    break;
1794                }
1795
1796                WorldObject* summoner = dynamic_cast<WorldObject*>(source);
1797
1798                if(!summoner)
1799                {
1800                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
1801                    break;
1802                }
1803
1804                GameObject *go = NULL;
1805                int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2;
1806
1807                CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY()));
1808                Cell cell(p);
1809                cell.data.Part.reserved = ALL_DISTRICT;
1810
1811                Trinity::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
1812                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(go,go_check);
1813
1814                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1815                CellLock<GridReadGuard> cell_lock(cell, p);
1816                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner));
1817
1818                if ( !go )
1819                {
1820                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong);
1821                    break;
1822                }
1823
1824                if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
1825                    go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
1826                    go->GetGoType()==GAMEOBJECT_TYPE_DOOR        ||
1827                    go->GetGoType()==GAMEOBJECT_TYPE_BUTTON      ||
1828                    go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
1829                {
1830                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong);
1831                    break;
1832                }
1833
1834                if( go->isSpawned() )
1835                    break;                                  //gameobject already spawned
1836
1837                go->SetLootState(GO_READY);
1838                go->SetRespawnTime(time_to_despawn);        //despawn object in ? seconds
1839
1840                MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go);
1841                break;
1842            }
1843            case SCRIPT_COMMAND_OPEN_DOOR:
1844            {
1845                if(!step.script->datalong)                  // door not specified
1846                {
1847                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door.");
1848                    break;
1849                }
1850
1851                if(!source)
1852                {
1853                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit.");
1854                    break;
1855                }
1856
1857                if(!source->isType(TYPEMASK_UNIT))          // must be any Unit (creature or player)
1858                {
1859                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
1860                    break;
1861                }
1862
1863                Unit* caster = (Unit*)source;
1864
1865                GameObject *door = NULL;
1866                int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
1867
1868                CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
1869                Cell cell(p);
1870                cell.data.Part.reserved = ALL_DISTRICT;
1871
1872                Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
1873                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
1874
1875                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1876                CellLock<GridReadGuard> cell_lock(cell, p);
1877                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
1878
1879                if ( !door )
1880                {
1881                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
1882                    break;
1883                }
1884                if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
1885                {
1886                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
1887                    break;
1888                }
1889
1890                if( !door->GetGoState() )
1891                    break;                                  //door already  open
1892
1893                door->UseDoorOrButton(time_to_close);
1894
1895                if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
1896                    ((GameObject*)target)->UseDoorOrButton(time_to_close);
1897                break;
1898            }
1899            case SCRIPT_COMMAND_CLOSE_DOOR:
1900            {
1901                if(!step.script->datalong)                  // guid for door not specified
1902                {
1903                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door.");
1904                    break;
1905                }
1906
1907                if(!source)
1908                {
1909                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit.");
1910                    break;
1911                }
1912
1913                if(!source->isType(TYPEMASK_UNIT))          // must be any Unit (creature or player)
1914                {
1915                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
1916                    break;
1917                }
1918
1919                Unit* caster = (Unit*)source;
1920
1921                GameObject *door = NULL;
1922                int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
1923
1924                CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
1925                Cell cell(p);
1926                cell.data.Part.reserved = ALL_DISTRICT;
1927
1928                Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
1929                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
1930
1931                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1932                CellLock<GridReadGuard> cell_lock(cell, p);
1933                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
1934
1935                if ( !door )
1936                {
1937                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong);
1938                    break;
1939                }
1940                if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
1941                {
1942                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType());
1943                    break;
1944                }
1945
1946                if( door->GetGoState() )
1947                    break;                                  //door already closed
1948
1949                door->UseDoorOrButton(time_to_open);
1950
1951                if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
1952                    ((GameObject*)target)->UseDoorOrButton(time_to_open);
1953
1954                break;
1955            }
1956            case SCRIPT_COMMAND_QUEST_EXPLORED:
1957            {
1958                if(!source)
1959                {
1960                    sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source.");
1961                    break;
1962                }
1963
1964                if(!target)
1965                {
1966                    sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target.");
1967                    break;
1968                }
1969
1970                // when script called for item spell casting then target == (unit or GO) and source is player
1971                WorldObject* worldObject;
1972                Player* player;
1973
1974                if(target->GetTypeId()==TYPEID_PLAYER)
1975                {
1976                    if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT)
1977                    {
1978                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId());
1979                        break;
1980                    }
1981
1982                    worldObject = (WorldObject*)source;
1983                    player = (Player*)target;
1984                }
1985                else
1986                {
1987                    if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT)
1988                    {
1989                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
1990                        break;
1991                    }
1992
1993                    if(source->GetTypeId()!=TYPEID_PLAYER)
1994                    {
1995                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId());
1996                        break;
1997                    }
1998
1999                    worldObject = (WorldObject*)target;
2000                    player = (Player*)source;
2001                }
2002
2003                // quest id and flags checked at script loading
2004                if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
2005                    (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) )
2006                    player->AreaExploredOrEventHappens(step.script->datalong);
2007                else
2008                    player->FailQuest(step.script->datalong);
2009
2010                break;
2011            }
2012
2013            case SCRIPT_COMMAND_ACTIVATE_OBJECT:
2014            {
2015                if(!source)
2016                {
2017                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster.");
2018                    break;
2019                }
2020
2021                if(!source->isType(TYPEMASK_UNIT))
2022                {
2023                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
2024                    break;
2025                }
2026
2027                if(!target)
2028                {
2029                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject.");
2030                    break;
2031                }
2032
2033                if(target->GetTypeId()!=TYPEID_GAMEOBJECT)
2034                {
2035                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
2036                    break;
2037                }
2038
2039                Unit* caster = (Unit*)source;
2040
2041                GameObject *go = (GameObject*)target;
2042
2043                go->Use(caster);
2044                break;
2045            }
2046
2047            case SCRIPT_COMMAND_REMOVE_AURA:
2048            {
2049                Object* cmdTarget = step.script->datalong2 ? source : target;
2050
2051                if(!cmdTarget)
2052                {
2053                    sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target");
2054                    break;
2055                }
2056
2057                if(!cmdTarget->isType(TYPEMASK_UNIT))
2058                {
2059                    sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
2060                    break;
2061                }
2062
2063                ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong);
2064                break;
2065            }
2066
2067            case SCRIPT_COMMAND_CAST_SPELL:
2068            {
2069                if(!source)
2070                {
2071                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster.");
2072                    break;
2073                }
2074
2075                if(!source->isType(TYPEMASK_UNIT))
2076                {
2077                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
2078                    break;
2079                }
2080
2081                Object* cmdTarget = step.script->datalong2 ? source : target;
2082
2083                if(!cmdTarget)
2084                {
2085                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 ? "source" : "target");
2086                    break;
2087                }
2088
2089                if(!cmdTarget->isType(TYPEMASK_UNIT))
2090                {
2091                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
2092                    break;
2093                }
2094
2095                Unit* spellTarget = (Unit*)cmdTarget;
2096
2097                //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
2098                ((Unit*)source)->CastSpell(spellTarget,step.script->datalong,false);
2099
2100                break;
2101            }
2102
2103            default:
2104                sLog.outError("Unknown script command %u called.",step.script->command);
2105                break;
2106        }
2107
2108        m_scriptSchedule.erase(iter);
2109
2110        iter = m_scriptSchedule.begin();
2111    }
2112    return;
2113}
2114
2115/// Send a packet to all players (except self if mentioned)
2116void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
2117{
2118    SessionMap::iterator itr;
2119    for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
2120    {
2121        if (itr->second &&
2122            itr->second->GetPlayer() &&
2123            itr->second->GetPlayer()->IsInWorld() &&
2124            itr->second != self &&
2125            (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
2126        {
2127            itr->second->SendPacket(packet);
2128        }
2129    }
2130}
2131
2132/// Send a System Message to all players (except self if mentioned)
2133void World::SendWorldText(int32 string_id, ...)
2134{
2135    std::vector<std::vector<WorldPacket*> > data_cache;     // 0 = default, i => i-1 locale index
2136
2137    for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2138    {
2139        if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
2140            continue;
2141
2142        uint32 loc_idx = itr->second->GetSessionDbLocaleIndex();
2143        uint32 cache_idx = loc_idx+1;
2144
2145        std::vector<WorldPacket*>* data_list;
2146
2147        // create if not cached yet
2148        if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty())
2149        {
2150            if(data_cache.size() < cache_idx+1)
2151                data_cache.resize(cache_idx+1);
2152
2153            data_list = &data_cache[cache_idx];
2154
2155            char const* text = objmgr.GetTrinityString(string_id,loc_idx);
2156
2157            char buf[1000];
2158
2159            va_list argptr;
2160            va_start( argptr, string_id );
2161            vsnprintf( buf,1000, text, argptr );
2162            va_end( argptr );
2163
2164            char* pos = &buf[0];
2165
2166            while(char* line = ChatHandler::LineFromMessage(pos))
2167            {
2168                WorldPacket* data = new WorldPacket();
2169                ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
2170                data_list->push_back(data);
2171            }
2172        }
2173        else
2174            data_list = &data_cache[cache_idx];
2175
2176        for(int i = 0; i < data_list->size(); ++i)
2177            itr->second->SendPacket((*data_list)[i]);
2178    }
2179
2180    // free memory
2181    for(int i = 0; i < data_cache.size(); ++i)
2182        for(int j = 0; j < data_cache[i].size(); ++j)
2183            delete data_cache[i][j];
2184}
2185
2186/// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
2187void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
2188{
2189    SessionMap::iterator itr;
2190    for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
2191    {
2192        if (itr->second &&
2193            itr->second->GetPlayer() &&
2194            itr->second->GetPlayer()->IsInWorld() &&
2195            itr->second->GetPlayer()->GetZoneId() == zone &&
2196            itr->second != self &&
2197            (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
2198        {
2199            itr->second->SendPacket(packet);
2200        }
2201    }
2202}
2203
2204/// Send a System Message to all players in the zone (except self if mentioned)
2205void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team)
2206{
2207    WorldPacket data;
2208    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL);
2209    SendZoneMessage(zone, &data, self,team);
2210}
2211
2212/// Kick (and save) all players
2213void World::KickAll()
2214{
2215    // session not removed at kick and will removed in next update tick
2216    for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2217        itr->second->KickPlayer();
2218}
2219
2220/// Kick (and save) all players with security level less `sec`
2221void World::KickAllLess(AccountTypes sec)
2222{
2223    // session not removed at kick and will removed in next update tick
2224    for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2225        if(itr->second->GetSecurity() < sec)
2226            itr->second->KickPlayer();
2227}
2228
2229/// Kick all queued players
2230void World::KickAllQueued()
2231{
2232    // session not removed at kick and will removed in next update tick
2233  //TODO here
2234//    for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr)
2235//        if(WorldSession* session = (*itr)->GetSession())
2236//            session->KickPlayer();
2237
2238    m_QueuedPlayer.empty();
2239}
2240
2241/// Kick (and save) the designated player
2242bool World::KickPlayer(std::string playerName)
2243{
2244    SessionMap::iterator itr;
2245
2246    // session not removed at kick and will removed in next update tick
2247    for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2248    {
2249        if(!itr->second)
2250            continue;
2251        Player *player = itr->second->GetPlayer();
2252        if(!player)
2253            continue;
2254        if( player->IsInWorld() )
2255        {
2256            if (playerName == player->GetName())
2257            {
2258                itr->second->KickPlayer();
2259                return true;
2260            }
2261        }
2262    }
2263    return false;
2264}
2265
2266/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
2267BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
2268{
2269    loginDatabase.escape_string(nameOrIP);
2270    loginDatabase.escape_string(reason);
2271    std::string safe_author=author;
2272    loginDatabase.escape_string(safe_author);
2273
2274    uint32 duration_secs = TimeStringToSecs(duration);
2275    QueryResult *resultAccounts = NULL;                     //used for kicking
2276
2277    ///- Update the database with ban information
2278        switch(mode)
2279    {
2280        case BAN_IP:
2281                        //No SQL injection as strings are escaped
2282                        resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
2283                        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());
2284                        break;
2285                case BAN_ACCOUNT:
2286                        //No SQL injection as string is escaped
2287                        resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
2288                        break;
2289                case BAN_CHARACTER:
2290                        //No SQL injection as string is escaped
2291                        resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str());
2292                        break;
2293                default:
2294                        return BAN_SYNTAX_ERROR;
2295    }
2296   
2297        if(!resultAccounts)
2298        {
2299                if(mode==BAN_IP)
2300            return BAN_SUCCESS;
2301                else
2302                        return BAN_NOTFOUND;                                // Nobody to ban
2303        }
2304
2305    ///- Disconnect all affected players (for IP it can be several)
2306    do
2307    {
2308        Field* fieldsAccount = resultAccounts->Fetch();
2309        uint32 account = fieldsAccount->GetUInt32();
2310
2311        if(mode!=BAN_IP)
2312                {
2313            //No SQL injection as strings are escaped
2314            loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
2315                account,duration_secs,safe_author.c_str(),reason.c_str());
2316                }
2317
2318        if (WorldSession* sess = FindSession(account))
2319            if(std::string(sess->GetPlayerName()) != author)
2320                sess->KickPlayer();
2321    }
2322    while( resultAccounts->NextRow() );
2323
2324    delete resultAccounts;
2325    return BAN_SUCCESS;
2326}
2327
2328/// Remove a ban from an account or IP address
2329bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
2330{
2331    if (mode == BAN_IP)
2332    {
2333        loginDatabase.escape_string(nameOrIP);
2334        loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
2335    }
2336    else
2337    {
2338        uint32 account=0;
2339        if (mode == BAN_ACCOUNT)
2340            account = accmgr.GetId (nameOrIP);
2341        else if (mode == BAN_CHARACTER)
2342            account = objmgr.GetPlayerAccountIdByPlayerName (nameOrIP);
2343
2344        if(!account)
2345            return false;
2346           
2347        //NO SQL injection as account is uint32
2348        loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
2349    }
2350    return true;
2351}
2352
2353/// Update the game time
2354void World::_UpdateGameTime()
2355{
2356    ///- update the time
2357    time_t thisTime = time(NULL);
2358    uint32 elapsed = uint32(thisTime - m_gameTime);
2359    m_gameTime = thisTime;
2360
2361    ///- if there is a shutdown timer
2362    if(m_ShutdownTimer > 0 && elapsed > 0)
2363    {
2364        ///- ... and it is overdue, stop the world (set m_stopEvent)
2365        if( m_ShutdownTimer <= elapsed )
2366        {
2367            if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
2368                m_stopEvent = true;
2369            else
2370                m_ShutdownTimer = 1;                        // minimum timer value to wait idle state
2371        }
2372        ///- ... else decrease it and if necessary display a shutdown countdown to the users
2373        else
2374        {
2375            m_ShutdownTimer -= elapsed;
2376
2377            ShutdownMsg();
2378        }
2379    }
2380}
2381
2382/// Shutdown the server
2383void World::ShutdownServ(uint32 time, uint32 options)
2384{
2385    m_ShutdownMask = options;
2386
2387    ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions)
2388    if(time==0)
2389    {
2390        if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
2391            m_stopEvent = true;
2392        else
2393            m_ShutdownTimer = 1;                            //So that the session count is re-evaluated at next world tick
2394    }
2395    ///- Else set the shutdown timer and warn users
2396    else
2397    {
2398        m_ShutdownTimer = time;
2399        ShutdownMsg(true);
2400    }
2401}
2402
2403/// Display a shutdown message to the user(s)
2404void World::ShutdownMsg(bool show, Player* player)
2405{
2406    // not show messages for idle shutdown mode
2407    if(m_ShutdownMask & SHUTDOWN_MASK_IDLE)
2408        return;
2409
2410    ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
2411    if ( show ||
2412        (m_ShutdownTimer < 10) ||
2413                                                            // < 30 sec; every 5 sec
2414        (m_ShutdownTimer<30        && (m_ShutdownTimer % 5         )==0) ||
2415                                                            // < 5 min ; every 1 min
2416        (m_ShutdownTimer<5*MINUTE  && (m_ShutdownTimer % MINUTE    )==0) ||
2417                                                            // < 30 min ; every 5 min
2418        (m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) ||
2419                                                            // < 12 h ; every 1 h
2420        (m_ShutdownTimer<12*HOUR   && (m_ShutdownTimer % HOUR      )==0) ||
2421                                                            // > 12 h ; every 12 h
2422        (m_ShutdownTimer>12*HOUR   && (m_ShutdownTimer % (12*HOUR) )==0))
2423    {
2424        std::string str = secsToTimeString(m_ShutdownTimer);
2425
2426        uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
2427
2428        SendServerMessage(msgid,str.c_str(),player);
2429        outstring_log("Server will %s in %s", (m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutdown"), str.c_str());
2430    }
2431}
2432
2433/// Cancel a planned server shutdown
2434void World::ShutdownCancel()
2435{
2436    if(!m_ShutdownTimer)
2437        return;
2438
2439    uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
2440
2441    m_ShutdownMask = 0;
2442    m_ShutdownTimer = 0;
2443    SendServerMessage(msgid);
2444
2445    DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"));
2446}
2447
2448/// Send a server message to the user(s)
2449void World::SendServerMessage(uint32 type, const char *text, Player* player)
2450{
2451    WorldPacket data(SMSG_SERVER_MESSAGE, 50);              // guess size
2452    data << uint32(type);
2453    if(type <= SERVER_MSG_STRING)
2454        data << text;
2455
2456    if(player)
2457        player->GetSession()->SendPacket(&data);
2458    else
2459        SendGlobalMessage( &data );
2460}
2461
2462void World::UpdateSessions( time_t diff )
2463{
2464    while(!addSessQueue.empty())
2465    {
2466      WorldSession* sess = addSessQueue.next ();
2467      AddSession_ (sess);
2468    }
2469       
2470    ///- Delete kicked sessions at add new session
2471    for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr)
2472        delete *itr;
2473    m_kicked_sessions.clear();
2474
2475    ///- Then send an update signal to remaining ones
2476    for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
2477    {
2478        next = itr;
2479        ++next;
2480
2481        if(!itr->second)
2482            continue;
2483
2484        ///- and remove not active sessions from the list
2485        if(!itr->second->Update(diff))                      // As interval = 0
2486        {
2487            delete itr->second;
2488            m_sessions.erase(itr);
2489        }
2490    }
2491}
2492
2493// This handles the issued and queued CLI commands
2494void World::ProcessCliCommands()
2495{
2496    if (cliCmdQueue.empty())
2497                return;
2498
2499    CliCommandHolder::Print* zprint;
2500    while (!cliCmdQueue.empty())
2501    {
2502        sLog.outDebug("CLI command under processing...");
2503        CliCommandHolder *command = cliCmdQueue.next();
2504
2505                zprint = command->m_print;
2506
2507                CliHandler(zprint).ParseCommands(command->m_command);
2508
2509        delete command;
2510    }
2511
2512    // print the console message here so it looks right
2513    zprint("TC> ");
2514}
2515
2516void World::InitResultQueue()
2517{
2518    m_resultQueue = new SqlResultQueue;
2519    CharacterDatabase.SetResultQueue(m_resultQueue);
2520}
2521
2522void World::UpdateResultQueue()
2523{
2524    m_resultQueue->Update();
2525}
2526
2527void World::UpdateRealmCharCount(uint32 accountId)
2528{
2529    CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId,
2530        "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId);
2531}
2532
2533void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId)
2534{
2535    if (resultCharCount)
2536    {
2537        Field *fields = resultCharCount->Fetch();
2538        uint32 charCount = fields[0].GetUInt32();
2539        delete resultCharCount;
2540        loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
2541        loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
2542    }
2543}
2544
2545void World::InitDailyQuestResetTime()
2546{
2547    time_t mostRecentQuestTime;
2548
2549    QueryResult* result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily");
2550    if(result)
2551    {
2552        Field *fields = result->Fetch();
2553
2554        mostRecentQuestTime = (time_t)fields[0].GetUInt64();
2555        delete result;
2556    }
2557    else
2558        mostRecentQuestTime = 0;
2559
2560    // client built-in time for reset is 6:00 AM
2561    // FIX ME: client not show day start time
2562    time_t curTime = time(NULL);
2563    tm localTm = *localtime(&curTime);
2564    localTm.tm_hour = 6;
2565    localTm.tm_min  = 0;
2566    localTm.tm_sec  = 0;
2567
2568    // current day reset time
2569    time_t curDayResetTime = mktime(&localTm);
2570
2571    // last reset time before current moment
2572    time_t resetTime = (curTime < curDayResetTime) ? curDayResetTime - DAY : curDayResetTime;
2573
2574    // need reset (if we have quest time before last reset time (not processed by some reason)
2575    if(mostRecentQuestTime && mostRecentQuestTime <= resetTime)
2576        m_NextDailyQuestReset = mostRecentQuestTime;
2577    else
2578    {
2579        // plan next reset time
2580        m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + DAY : curDayResetTime;
2581    }
2582}
2583
2584void World::ResetDailyQuests()
2585{
2586    sLog.outDetail("Daily quests reset for all characters.");
2587    CharacterDatabase.Execute("DELETE FROM character_queststatus_daily");
2588    for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2589        if(itr->second->GetPlayer())
2590            itr->second->GetPlayer()->ResetDailyQuestStatus();
2591}
2592
2593void World::SetPlayerLimit( int32 limit, bool needUpdate )
2594{
2595    if(limit < -SEC_ADMINISTRATOR)
2596        limit = -SEC_ADMINISTRATOR;
2597
2598    // lock update need
2599    bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit);
2600
2601    m_playerLimit = limit;
2602
2603    if(db_update_need)
2604        loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
2605}
2606
2607void World::UpdateMaxSessionCounters()
2608{
2609    m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size()));
2610    m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size()));
2611}
Note: See TracBrowser for help on using the browser.