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

Revision 138, 106.2 kB (checked in by yumileroy, 17 years ago)

[svn] Enable linked spells: cast spells/remove auras when spells casted/spells hitting/auras removed. Add new table "spell_linked_spell". Some illustrations provided in sql.
Let trigger creature cast AOE spells when summoned. Illustration provided in sql.
Let active creatures always visible if possible. (seems does not work for now, need to find out why)

Original author: megamage
Date: 2008-10-30 11:32:10-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 linked spells..." );
1100    spellmgr.LoadSpellLinked();
1101
1102    sLog.outString( "Loading player Create Info & Level Stats..." );
1103    objmgr.LoadPlayerInfo();
1104
1105    sLog.outString( "Loading Exploration BaseXP Data..." );
1106    objmgr.LoadExplorationBaseXP();
1107
1108    sLog.outString( "Loading Pet Name Parts..." );
1109    objmgr.LoadPetNames();
1110
1111    sLog.outString( "Loading the max pet number..." );
1112    objmgr.LoadPetNumber();
1113
1114    sLog.outString( "Loading pet level stats..." );
1115    objmgr.LoadPetLevelInfo();
1116
1117    sLog.outString( "Loading Player Corpses..." );
1118    objmgr.LoadCorpses();
1119
1120    sLog.outString( "Loading Disabled Spells..." );
1121    objmgr.LoadSpellDisabledEntrys();
1122
1123    sLog.outString( "Loading Loot Tables..." );
1124    LoadLootTables();
1125
1126    sLog.outString( "Loading Skill Discovery Table..." );
1127    LoadSkillDiscoveryTable();
1128
1129    sLog.outString( "Loading Skill Extra Item Table..." );
1130    LoadSkillExtraItemTable();
1131
1132    sLog.outString( "Loading Skill Fishing base level requirements..." );
1133    objmgr.LoadFishingBaseSkillLevel();
1134
1135    ///- Load dynamic data tables from the database
1136    sLog.outString( "Loading Auctions..." );
1137    objmgr.LoadAuctionItems();
1138    objmgr.LoadAuctions();
1139
1140    sLog.outString( "Loading Guilds..." );
1141    objmgr.LoadGuilds();
1142
1143    sLog.outString( "Loading ArenaTeams..." );
1144    objmgr.LoadArenaTeams();
1145
1146    sLog.outString( "Loading Groups..." );
1147    objmgr.LoadGroups();
1148
1149    sLog.outString( "Loading ReservedNames..." );
1150    objmgr.LoadReservedPlayersNames();
1151
1152    sLog.outString( "Loading GameObject for quests..." );
1153    objmgr.LoadGameObjectForQuests();
1154
1155    sLog.outString( "Loading BattleMasters..." );
1156    objmgr.LoadBattleMastersEntry();
1157
1158    sLog.outString( "Loading GameTeleports..." );
1159    objmgr.LoadGameTele();
1160
1161    sLog.outString( "Loading Npc Text Id..." );
1162    objmgr.LoadNpcTextId();                                 // must be after load Creature and NpcText
1163
1164    sLog.outString( "Loading vendors..." );
1165    objmgr.LoadVendors();                                   // must be after load CreatureTemplate and ItemTemplate
1166
1167    sLog.outString( "Loading trainers..." );
1168    objmgr.LoadTrainerSpell();                              // must be after load CreatureTemplate
1169
1170    sLog.outString( "Loading Waypoints..." );
1171    WaypointMgr.Load();
1172
1173    ///- Handle outdated emails (delete/return)
1174    sLog.outString( "Returning old mails..." );
1175    objmgr.ReturnOrDeleteOldMails(false);
1176
1177    ///- Load and initialize scripts
1178    sLog.outString( "Loading Scripts..." );
1179    objmgr.LoadQuestStartScripts();                         // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1180    objmgr.LoadQuestEndScripts();                           // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1181    objmgr.LoadSpellScripts();                              // must be after load Creature/Gameobject(Template/Data)
1182    objmgr.LoadGameObjectScripts();                         // must be after load Creature/Gameobject(Template/Data)
1183    objmgr.LoadEventScripts();                              // must be after load Creature/Gameobject(Template/Data)
1184
1185    sLog.outString( "Initializing Scripts..." );
1186    if(!LoadScriptingModule())
1187        exit(1);
1188
1189    ///- Initialize game time and timers
1190    sLog.outString( "DEBUG:: Initialize game time and timers" );
1191    m_gameTime = time(NULL);
1192    m_startTime=m_gameTime;
1193
1194    tm local;
1195    time_t curr;
1196    time(&curr);
1197    local=*(localtime(&curr));                              // dereference and assign
1198    char isoDate[128];
1199    sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
1200        local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
1201
1202    WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', %ld, 0)", isoDate, m_startTime );
1203
1204    m_timers[WUPDATE_OBJECTS].SetInterval(0);
1205    m_timers[WUPDATE_SESSIONS].SetInterval(0);
1206    m_timers[WUPDATE_WEATHERS].SetInterval(1000);
1207    m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000);    //set auction update interval to 1 minute
1208    m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
1209                                                            //Update "uptime" table based on configuration entry in minutes.
1210    m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000);  //erase corpses every 20 minutes
1211
1212    //to set mailtimer to return mails every day between 4 and 5 am
1213    //mailtimer is increased when updating auctions
1214    //one second is 1000 -(tested on win system)
1215    mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
1216                                                            //1440
1217    mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
1218    sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
1219
1220    ///- Initilize static helper structures
1221    AIRegistry::Initialize();
1222    WaypointMovementGenerator<Creature>::Initialize();
1223    Player::InitVisibleBits();
1224
1225    ///- Initialize MapManager
1226    sLog.outString( "Starting Map System" );
1227    MapManager::Instance().Initialize();
1228
1229    ///- Initialize Battlegrounds
1230    sLog.outString( "Starting BattleGround System" );
1231    sBattleGroundMgr.CreateInitialBattleGrounds();
1232    sBattleGroundMgr.InitAutomaticArenaPointDistribution();
1233
1234    ///- Initialize outdoor pvp
1235    sLog.outString( "Starting Outdoor PvP System" );
1236    sOutdoorPvPMgr.InitOutdoorPvP();
1237
1238    //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
1239    sLog.outString( "Loading Transports..." );
1240    MapManager::Instance().LoadTransports();
1241
1242    sLog.outString("Deleting expired bans..." );
1243    loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
1244
1245    sLog.outString("Calculate next daily quest reset time..." );
1246    InitDailyQuestResetTime();
1247
1248    sLog.outString("Starting Game Event system..." );
1249    uint32 nextGameEvent = gameeventmgr.Initialize();
1250    m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);    //depend on next event
1251
1252    sLog.outString( "WORLD: World initialized" );
1253}
1254void World::DetectDBCLang()
1255{
1256    uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255);
1257
1258    if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE)
1259    {
1260        sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE);
1261        m_lang_confid = LOCALE_enUS;
1262    }
1263
1264    ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1);
1265
1266    std::string availableLocalsStr;
1267
1268    int default_locale = MAX_LOCALE;
1269    for (int i = MAX_LOCALE-1; i >= 0; --i)
1270    {
1271        if ( strlen(race->name[i]) > 0)                     // check by race names
1272        {
1273            default_locale = i;
1274            m_availableDbcLocaleMask |= (1 << i);
1275            availableLocalsStr += localeNames[i];
1276            availableLocalsStr += " ";
1277        }
1278    }
1279
1280    if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE &&
1281        (m_availableDbcLocaleMask & (1 << m_lang_confid)) )
1282    {
1283        default_locale = m_lang_confid;
1284    }
1285
1286    if(default_locale >= MAX_LOCALE)
1287    {
1288        sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)");
1289        exit(1);
1290    }
1291
1292    m_defaultDbcLocale = LocaleConstant(default_locale);
1293
1294    sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
1295}
1296
1297/// Update the World !
1298void World::Update(time_t diff)
1299{
1300    ///- Update the different timers
1301    for(int i = 0; i < WUPDATE_COUNT; i++)
1302        if(m_timers[i].GetCurrent()>=0)
1303            m_timers[i].Update(diff);
1304    else m_timers[i].SetCurrent(0);
1305
1306    ///- Update the game time and check for shutdown time
1307    _UpdateGameTime();
1308
1309    /// Handle daily quests reset time
1310    if(m_gameTime > m_NextDailyQuestReset)
1311    {
1312        ResetDailyQuests();
1313        m_NextDailyQuestReset += DAY;
1314    }
1315
1316    /// <ul><li> Handle auctions when the timer has passed
1317    if (m_timers[WUPDATE_AUCTIONS].Passed())
1318    {
1319        m_timers[WUPDATE_AUCTIONS].Reset();
1320
1321        ///- Update mails (return old mails with item, or delete them)
1322        //(tested... works on win)
1323        if (++mail_timer > mail_timer_expires)
1324        {
1325            mail_timer = 0;
1326            objmgr.ReturnOrDeleteOldMails(true);
1327        }
1328
1329        AuctionHouseObject* AuctionMap;
1330        for (int i = 0; i < 3; i++)
1331        {
1332            switch (i)
1333            {
1334                case 0:
1335                    AuctionMap = objmgr.GetAuctionsMap( 6 );//horde
1336                    break;
1337                case 1:
1338                    AuctionMap = objmgr.GetAuctionsMap( 2 );//alliance
1339                    break;
1340                case 2:
1341                    AuctionMap = objmgr.GetAuctionsMap( 7 );//neutral
1342                    break;
1343            }
1344
1345            ///- Handle expired auctions
1346            AuctionHouseObject::AuctionEntryMap::iterator itr,next;
1347            for (itr = AuctionMap->GetAuctionsBegin(); itr != AuctionMap->GetAuctionsEnd();itr = next)
1348            {
1349                next = itr;
1350                ++next;
1351                if (m_gameTime > (itr->second->time))
1352                {
1353                    ///- Either cancel the auction if there was no bidder
1354                    if (itr->second->bidder == 0)
1355                    {
1356                        objmgr.SendAuctionExpiredMail( itr->second );
1357                    }
1358                    ///- Or perform the transaction
1359                    else
1360                    {
1361                        //we should send an "item sold" message if the seller is online
1362                        //we send the item to the winner
1363                        //we send the money to the seller
1364                        objmgr.SendAuctionSuccessfulMail( itr->second );
1365                        objmgr.SendAuctionWonMail( itr->second );
1366                    }
1367
1368                    ///- In any case clear the auction
1369                    //No SQL injection (Id is integer)
1370                    CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",itr->second->Id);
1371                    objmgr.RemoveAItem(itr->second->item_guidlow);
1372                    delete itr->second;
1373                    AuctionMap->RemoveAuction(itr->first);
1374                }
1375            }
1376        }
1377    }
1378
1379    /// <li> Handle session updates when the timer has passed
1380    if (m_timers[WUPDATE_SESSIONS].Passed())
1381    {
1382        m_timers[WUPDATE_SESSIONS].Reset();
1383
1384        UpdateSessions(diff);
1385    }
1386
1387    /// <li> Handle weather updates when the timer has passed
1388    if (m_timers[WUPDATE_WEATHERS].Passed())
1389    {
1390        m_timers[WUPDATE_WEATHERS].Reset();
1391
1392        ///- Send an update signal to Weather objects
1393        WeatherMap::iterator itr, next;
1394        for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next)
1395        {
1396            next = itr;
1397            ++next;
1398
1399            ///- and remove Weather objects for zones with no player
1400                                                            //As interval > WorldTick
1401            if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval()))
1402            {
1403                delete itr->second;
1404                m_weathers.erase(itr);
1405            }
1406        }
1407    }
1408    /// <li> Update uptime table
1409    if (m_timers[WUPDATE_UPTIME].Passed())
1410    {
1411        uint32 tmpDiff = (m_gameTime - m_startTime);
1412        uint32 maxClientsNum = sWorld.GetMaxActiveSessionCount();
1413
1414        m_timers[WUPDATE_UPTIME].Reset();
1415        WorldDatabase.PExecute("UPDATE uptime SET uptime = %d, maxplayers = %d WHERE starttime = " I64FMTD, tmpDiff, maxClientsNum, uint64(m_startTime));
1416    }
1417
1418    /// <li> Handle all other objects
1419    if (m_timers[WUPDATE_OBJECTS].Passed())
1420    {
1421        m_timers[WUPDATE_OBJECTS].Reset();
1422        ///- Update objects when the timer has passed (maps, transport, creatures,...)
1423        MapManager::Instance().Update(diff);                // As interval = 0
1424
1425        ///- Process necessary scripts
1426        if (!m_scriptSchedule.empty())
1427            ScriptsProcess();
1428
1429        sBattleGroundMgr.Update(diff);
1430
1431        sOutdoorPvPMgr.Update(diff);
1432    }
1433
1434    // execute callbacks from sql queries that were queued recently
1435    UpdateResultQueue();
1436
1437    ///- Erase corpses once every 20 minutes
1438    if (m_timers[WUPDATE_CORPSES].Passed())
1439    {
1440        m_timers[WUPDATE_CORPSES].Reset();
1441
1442        CorpsesErase();
1443    }
1444
1445    ///- Process Game events when necessary
1446    if (m_timers[WUPDATE_EVENTS].Passed())
1447    {
1448        m_timers[WUPDATE_EVENTS].Reset();                   // to give time for Update() to be processed
1449        uint32 nextGameEvent = gameeventmgr.Update();
1450        m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
1451        m_timers[WUPDATE_EVENTS].Reset();
1452    }
1453
1454    MapManager::Instance().DoDelayedMovesAndRemoves(); ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
1455
1456    // update the instance reset times
1457    sInstanceSaveManager.Update();
1458
1459    // And last, but not least handle the issued cli commands
1460    ProcessCliCommands();
1461}
1462
1463void World::ForceGameEventUpdate()
1464{
1465    m_timers[WUPDATE_EVENTS].Reset();                   // to give time for Update() to be processed
1466    uint32 nextGameEvent = gameeventmgr.Update();
1467    m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
1468    m_timers[WUPDATE_EVENTS].Reset();
1469}
1470
1471/// Put scripts in the execution queue
1472void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target)
1473{
1474    ///- Find the script map
1475    ScriptMapMap::const_iterator s = scripts.find(id);
1476    if (s == scripts.end())
1477        return;
1478
1479    // prepare static data
1480    uint64 sourceGUID = source->GetGUID();
1481    uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
1482    uint64 ownerGUID  = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
1483
1484    ///- Schedule script execution for all scripts in the script map
1485    ScriptMap const *s2 = &(s->second);
1486    bool immedScript = false;
1487    for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
1488    {
1489        ScriptAction sa;
1490        sa.sourceGUID = sourceGUID;
1491        sa.targetGUID = targetGUID;
1492        sa.ownerGUID  = ownerGUID;
1493
1494        sa.script = &iter->second;
1495        m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + iter->first, sa));
1496        if (iter->first == 0)
1497            immedScript = true;
1498    }
1499    ///- If one of the effects should be immediate, launch the script execution
1500    if (immedScript)
1501        ScriptsProcess();
1502}
1503
1504void World::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
1505{
1506    // NOTE: script record _must_ exist until command executed
1507
1508    // prepare static data
1509    uint64 sourceGUID = source->GetGUID();
1510    uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
1511    uint64 ownerGUID  = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
1512
1513    ScriptAction sa;
1514    sa.sourceGUID = sourceGUID;
1515    sa.targetGUID = targetGUID;
1516    sa.ownerGUID  = ownerGUID;
1517
1518    sa.script = &script;
1519    m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(m_gameTime + delay, sa));
1520
1521    ///- If effects should be immediate, launch the script execution
1522    if(delay == 0)
1523        ScriptsProcess();
1524}
1525
1526/// Process queued scripts
1527void World::ScriptsProcess()
1528{
1529    if (m_scriptSchedule.empty())
1530        return;
1531
1532    ///- Process overdue queued scripts
1533    std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin();
1534                                                            // ok as multimap is a *sorted* associative container
1535    while (!m_scriptSchedule.empty() && (iter->first <= m_gameTime))
1536    {
1537        ScriptAction const& step = iter->second;
1538
1539        Object* source = NULL;
1540
1541        if(step.sourceGUID)
1542        {
1543            switch(GUID_HIPART(step.sourceGUID))
1544            {
1545                case HIGHGUID_ITEM:
1546                    // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM
1547                    {
1548                        Player* player = HashMapHolder<Player>::Find(step.ownerGUID);
1549                        if(player)
1550                            source = player->GetItemByGuid(step.sourceGUID);
1551                        break;
1552                    }
1553                case HIGHGUID_UNIT:
1554                    source = HashMapHolder<Creature>::Find(step.sourceGUID);
1555                    break;
1556                case HIGHGUID_PET:
1557                    source = HashMapHolder<Pet>::Find(step.sourceGUID);
1558                    break;
1559                case HIGHGUID_PLAYER:
1560                    source = HashMapHolder<Player>::Find(step.sourceGUID);
1561                    break;
1562                case HIGHGUID_GAMEOBJECT:
1563                    source = HashMapHolder<GameObject>::Find(step.sourceGUID);
1564                    break;
1565                case HIGHGUID_CORPSE:
1566                    source = HashMapHolder<Corpse>::Find(step.sourceGUID);
1567                    break;
1568                default:
1569                    sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID));
1570                    break;
1571            }
1572        }
1573
1574        Object* target = NULL;
1575
1576        if(step.targetGUID)
1577        {
1578            switch(GUID_HIPART(step.targetGUID))
1579            {
1580                case HIGHGUID_UNIT:
1581                    target = HashMapHolder<Creature>::Find(step.targetGUID);
1582                    break;
1583                case HIGHGUID_PET:
1584                    target = HashMapHolder<Pet>::Find(step.targetGUID);
1585                    break;
1586                case HIGHGUID_PLAYER:                       // empty GUID case also
1587                    target = HashMapHolder<Player>::Find(step.targetGUID);
1588                    break;
1589                case HIGHGUID_GAMEOBJECT:
1590                    target = HashMapHolder<GameObject>::Find(step.targetGUID);
1591                    break;
1592                case HIGHGUID_CORPSE:
1593                    target = HashMapHolder<Corpse>::Find(step.targetGUID);
1594                    break;
1595                default:
1596                    sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID));
1597                    break;
1598            }
1599        }
1600
1601        switch (step.script->command)
1602        {
1603            case SCRIPT_COMMAND_TALK:
1604            {
1605                if(!source)
1606                {
1607                    sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature.");
1608                    break;
1609                }
1610
1611                if(source->GetTypeId()!=TYPEID_UNIT)
1612                {
1613                    sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1614                    break;
1615                }
1616                if(step.script->datalong > 3)
1617                {
1618                    sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong);
1619                    break;
1620                }
1621
1622                uint64 unit_target = target ? target->GetGUID() : 0;
1623
1624                //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text
1625                switch(step.script->datalong)
1626                {
1627                    case 0:                                 // Say
1628                        ((Creature *)source)->Say(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target);
1629                        break;
1630                    case 1:                                 // Whisper
1631                        if(!unit_target)
1632                        {
1633                            sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong);
1634                            break;
1635                        }
1636                        ((Creature *)source)->Whisper(step.script->datatext.c_str(),unit_target);
1637                        break;
1638                    case 2:                                 // Yell
1639                        ((Creature *)source)->Yell(step.script->datatext.c_str(), LANG_UNIVERSAL, unit_target);
1640                        break;
1641                    case 3:                                 // Emote text
1642                        ((Creature *)source)->TextEmote(step.script->datatext.c_str(), unit_target);
1643                        break;
1644                    default:
1645                        break;                              // must be already checked at load
1646                }
1647                break;
1648            }
1649
1650            case SCRIPT_COMMAND_EMOTE:
1651                if(!source)
1652                {
1653                    sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature.");
1654                    break;
1655                }
1656
1657                if(source->GetTypeId()!=TYPEID_UNIT)
1658                {
1659                    sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1660                    break;
1661                }
1662
1663                ((Creature *)source)->HandleEmoteCommand(step.script->datalong);
1664                break;
1665            case SCRIPT_COMMAND_FIELD_SET:
1666                if(!source)
1667                {
1668                    sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object.");
1669                    break;
1670                }
1671                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1672                {
1673                    sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
1674                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1675                    break;
1676                }
1677
1678                source->SetUInt32Value(step.script->datalong, step.script->datalong2);
1679                break;
1680            case SCRIPT_COMMAND_MOVE_TO:
1681                if(!source)
1682                {
1683                    sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature.");
1684                    break;
1685                }
1686
1687                if(source->GetTypeId()!=TYPEID_UNIT)
1688                {
1689                    sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
1690                    break;
1691                }
1692                ((Unit *)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, ((Unit *)source)->GetUnitMovementFlags(), step.script->datalong2 );
1693                MapManager::Instance().GetMap(((Unit *)source)->GetMapId(), ((Unit *)source))->CreatureRelocation(((Creature *)source), step.script->x, step.script->y, step.script->z, 0);
1694                break;
1695            case SCRIPT_COMMAND_FLAG_SET:
1696                if(!source)
1697                {
1698                    sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object.");
1699                    break;
1700                }
1701                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1702                {
1703                    sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
1704                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1705                    break;
1706                }
1707
1708                source->SetFlag(step.script->datalong, step.script->datalong2);
1709                break;
1710            case SCRIPT_COMMAND_FLAG_REMOVE:
1711                if(!source)
1712                {
1713                    sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object.");
1714                    break;
1715                }
1716                if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
1717                {
1718                    sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).",
1719                        step.script->datalong,source->GetValuesCount(),source->GetTypeId());
1720                    break;
1721                }
1722
1723                source->RemoveFlag(step.script->datalong, step.script->datalong2);
1724                break;
1725
1726            case SCRIPT_COMMAND_TELEPORT_TO:
1727            {
1728                // accept player in any one from target/source arg
1729                if (!target && !source)
1730                {
1731                    sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object.");
1732                    break;
1733                }
1734
1735                                                            // must be only Player
1736                if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER))
1737                {
1738                    sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
1739                    break;
1740                }
1741
1742                Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source;
1743
1744                pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
1745                break;
1746            }
1747
1748            case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
1749            {
1750                if(!step.script->datalong)                  // creature not specified
1751                {
1752                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature.");
1753                    break;
1754                }
1755
1756                if(!source)
1757                {
1758                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object.");
1759                    break;
1760                }
1761
1762                WorldObject* summoner = dynamic_cast<WorldObject*>(source);
1763
1764                if(!summoner)
1765                {
1766                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
1767                    break;
1768                }
1769
1770                float x = step.script->x;
1771                float y = step.script->y;
1772                float z = step.script->z;
1773                float o = step.script->o;
1774
1775                Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2);
1776                if (!pCreature)
1777                {
1778                    sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong);
1779                    break;
1780                }
1781
1782                break;
1783            }
1784
1785            case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
1786            {
1787                if(!step.script->datalong)                  // gameobject not specified
1788                {
1789                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject.");
1790                    break;
1791                }
1792
1793                if(!source)
1794                {
1795                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object.");
1796                    break;
1797                }
1798
1799                WorldObject* summoner = dynamic_cast<WorldObject*>(source);
1800
1801                if(!summoner)
1802                {
1803                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
1804                    break;
1805                }
1806
1807                GameObject *go = NULL;
1808                int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2;
1809
1810                CellPair p(Trinity::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY()));
1811                Cell cell(p);
1812                cell.data.Part.reserved = ALL_DISTRICT;
1813
1814                Trinity::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
1815                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(go,go_check);
1816
1817                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1818                CellLock<GridReadGuard> cell_lock(cell, p);
1819                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(summoner->GetMapId(), summoner));
1820
1821                if ( !go )
1822                {
1823                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong);
1824                    break;
1825                }
1826
1827                if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
1828                    go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
1829                    go->GetGoType()==GAMEOBJECT_TYPE_DOOR        ||
1830                    go->GetGoType()==GAMEOBJECT_TYPE_BUTTON      ||
1831                    go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
1832                {
1833                    sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong);
1834                    break;
1835                }
1836
1837                if( go->isSpawned() )
1838                    break;                                  //gameobject already spawned
1839
1840                go->SetLootState(GO_READY);
1841                go->SetRespawnTime(time_to_despawn);        //despawn object in ? seconds
1842
1843                MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go);
1844                break;
1845            }
1846            case SCRIPT_COMMAND_OPEN_DOOR:
1847            {
1848                if(!step.script->datalong)                  // door not specified
1849                {
1850                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door.");
1851                    break;
1852                }
1853
1854                if(!source)
1855                {
1856                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit.");
1857                    break;
1858                }
1859
1860                if(!source->isType(TYPEMASK_UNIT))          // must be any Unit (creature or player)
1861                {
1862                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
1863                    break;
1864                }
1865
1866                Unit* caster = (Unit*)source;
1867
1868                GameObject *door = NULL;
1869                int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
1870
1871                CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
1872                Cell cell(p);
1873                cell.data.Part.reserved = ALL_DISTRICT;
1874
1875                Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
1876                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
1877
1878                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1879                CellLock<GridReadGuard> cell_lock(cell, p);
1880                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
1881
1882                if ( !door )
1883                {
1884                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
1885                    break;
1886                }
1887                if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
1888                {
1889                    sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
1890                    break;
1891                }
1892
1893                if( !door->GetGoState() )
1894                    break;                                  //door already  open
1895
1896                door->UseDoorOrButton(time_to_close);
1897
1898                if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
1899                    ((GameObject*)target)->UseDoorOrButton(time_to_close);
1900                break;
1901            }
1902            case SCRIPT_COMMAND_CLOSE_DOOR:
1903            {
1904                if(!step.script->datalong)                  // guid for door not specified
1905                {
1906                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door.");
1907                    break;
1908                }
1909
1910                if(!source)
1911                {
1912                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit.");
1913                    break;
1914                }
1915
1916                if(!source->isType(TYPEMASK_UNIT))          // must be any Unit (creature or player)
1917                {
1918                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
1919                    break;
1920                }
1921
1922                Unit* caster = (Unit*)source;
1923
1924                GameObject *door = NULL;
1925                int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
1926
1927                CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
1928                Cell cell(p);
1929                cell.data.Part.reserved = ALL_DISTRICT;
1930
1931                Trinity::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
1932                Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(door,go_check);
1933
1934                TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
1935                CellLock<GridReadGuard> cell_lock(cell, p);
1936                cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(caster->GetMapId(), (Unit*)source));
1937
1938                if ( !door )
1939                {
1940                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong);
1941                    break;
1942                }
1943                if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
1944                {
1945                    sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType());
1946                    break;
1947                }
1948
1949                if( door->GetGoState() )
1950                    break;                                  //door already closed
1951
1952                door->UseDoorOrButton(time_to_open);
1953
1954                if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
1955                    ((GameObject*)target)->UseDoorOrButton(time_to_open);
1956
1957                break;
1958            }
1959            case SCRIPT_COMMAND_QUEST_EXPLORED:
1960            {
1961                if(!source)
1962                {
1963                    sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source.");
1964                    break;
1965                }
1966
1967                if(!target)
1968                {
1969                    sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target.");
1970                    break;
1971                }
1972
1973                // when script called for item spell casting then target == (unit or GO) and source is player
1974                WorldObject* worldObject;
1975                Player* player;
1976
1977                if(target->GetTypeId()==TYPEID_PLAYER)
1978                {
1979                    if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT)
1980                    {
1981                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId());
1982                        break;
1983                    }
1984
1985                    worldObject = (WorldObject*)source;
1986                    player = (Player*)target;
1987                }
1988                else
1989                {
1990                    if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT)
1991                    {
1992                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
1993                        break;
1994                    }
1995
1996                    if(source->GetTypeId()!=TYPEID_PLAYER)
1997                    {
1998                        sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId());
1999                        break;
2000                    }
2001
2002                    worldObject = (WorldObject*)target;
2003                    player = (Player*)source;
2004                }
2005
2006                // quest id and flags checked at script loading
2007                if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
2008                    (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) )
2009                    player->AreaExploredOrEventHappens(step.script->datalong);
2010                else
2011                    player->FailQuest(step.script->datalong);
2012
2013                break;
2014            }
2015
2016            case SCRIPT_COMMAND_ACTIVATE_OBJECT:
2017            {
2018                if(!source)
2019                {
2020                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster.");
2021                    break;
2022                }
2023
2024                if(!source->isType(TYPEMASK_UNIT))
2025                {
2026                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
2027                    break;
2028                }
2029
2030                if(!target)
2031                {
2032                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject.");
2033                    break;
2034                }
2035
2036                if(target->GetTypeId()!=TYPEID_GAMEOBJECT)
2037                {
2038                    sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
2039                    break;
2040                }
2041
2042                Unit* caster = (Unit*)source;
2043
2044                GameObject *go = (GameObject*)target;
2045
2046                go->Use(caster);
2047                break;
2048            }
2049
2050            case SCRIPT_COMMAND_REMOVE_AURA:
2051            {
2052                Object* cmdTarget = step.script->datalong2 ? source : target;
2053
2054                if(!cmdTarget)
2055                {
2056                    sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target");
2057                    break;
2058                }
2059
2060                if(!cmdTarget->isType(TYPEMASK_UNIT))
2061                {
2062                    sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
2063                    break;
2064                }
2065
2066                ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong);
2067                break;
2068            }
2069
2070            case SCRIPT_COMMAND_CAST_SPELL:
2071            {
2072                if(!source)
2073                {
2074                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster.");
2075                    break;
2076                }
2077
2078                if(!source->isType(TYPEMASK_UNIT))
2079                {
2080                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
2081                    break;
2082                }
2083
2084                Object* cmdTarget = step.script->datalong2 ? source : target;
2085
2086                if(!cmdTarget)
2087                {
2088                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 ? "source" : "target");
2089                    break;
2090                }
2091
2092                if(!cmdTarget->isType(TYPEMASK_UNIT))
2093                {
2094                    sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
2095                    break;
2096                }
2097
2098                Unit* spellTarget = (Unit*)cmdTarget;
2099
2100                //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
2101                ((Unit*)source)->CastSpell(spellTarget,step.script->datalong,false);
2102
2103                break;
2104            }
2105
2106            default:
2107                sLog.outError("Unknown script command %u called.",step.script->command);
2108                break;
2109        }
2110
2111        m_scriptSchedule.erase(iter);
2112
2113        iter = m_scriptSchedule.begin();
2114    }
2115    return;
2116}
2117
2118/// Send a packet to all players (except self if mentioned)
2119void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
2120{
2121    SessionMap::iterator itr;
2122    for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
2123    {
2124        if (itr->second &&
2125            itr->second->GetPlayer() &&
2126            itr->second->GetPlayer()->IsInWorld() &&
2127            itr->second != self &&
2128            (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
2129        {
2130            itr->second->SendPacket(packet);
2131        }
2132    }
2133}
2134
2135/// Send a System Message to all players (except self if mentioned)
2136void World::SendWorldText(int32 string_id, ...)
2137{
2138    std::vector<std::vector<WorldPacket*> > data_cache;     // 0 = default, i => i-1 locale index
2139
2140    for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2141    {
2142        if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
2143            continue;
2144
2145        uint32 loc_idx = itr->second->GetSessionDbLocaleIndex();
2146        uint32 cache_idx = loc_idx+1;
2147
2148        std::vector<WorldPacket*>* data_list;
2149
2150        // create if not cached yet
2151        if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty())
2152        {
2153            if(data_cache.size() < cache_idx+1)
2154                data_cache.resize(cache_idx+1);
2155
2156            data_list = &data_cache[cache_idx];
2157
2158            char const* text = objmgr.GetTrinityString(string_id,loc_idx);
2159
2160            char buf[1000];
2161
2162            va_list argptr;
2163            va_start( argptr, string_id );
2164            vsnprintf( buf,1000, text, argptr );
2165            va_end( argptr );
2166
2167            char* pos = &buf[0];
2168
2169            while(char* line = ChatHandler::LineFromMessage(pos))
2170            {
2171                WorldPacket* data = new WorldPacket();
2172                ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
2173                data_list->push_back(data);
2174            }
2175        }
2176        else
2177            data_list = &data_cache[cache_idx];
2178
2179        for(int i = 0; i < data_list->size(); ++i)
2180            itr->second->SendPacket((*data_list)[i]);
2181    }
2182
2183    // free memory
2184    for(int i = 0; i < data_cache.size(); ++i)
2185        for(int j = 0; j < data_cache[i].size(); ++j)
2186            delete data_cache[i][j];
2187}
2188
2189/// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
2190void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
2191{
2192    SessionMap::iterator itr;
2193    for (itr = m_sessions.begin(); itr != m_sessions.end(); itr++)
2194    {
2195        if (itr->second &&
2196            itr->second->GetPlayer() &&
2197            itr->second->GetPlayer()->IsInWorld() &&
2198            itr->second->GetPlayer()->GetZoneId() == zone &&
2199            itr->second != self &&
2200            (team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
2201        {
2202            itr->second->SendPacket(packet);
2203        }
2204    }
2205}
2206
2207/// Send a System Message to all players in the zone (except self if mentioned)
2208void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team)
2209{
2210    WorldPacket data;
2211    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL);
2212    SendZoneMessage(zone, &data, self,team);
2213}
2214
2215/// Kick (and save) all players
2216void World::KickAll()
2217{
2218    // session not removed at kick and will removed in next update tick
2219    for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2220        itr->second->KickPlayer();
2221}
2222
2223/// Kick (and save) all players with security level less `sec`
2224void World::KickAllLess(AccountTypes sec)
2225{
2226    // session not removed at kick and will removed in next update tick
2227    for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2228        if(itr->second->GetSecurity() < sec)
2229            itr->second->KickPlayer();
2230}
2231
2232/// Kick all queued players
2233void World::KickAllQueued()
2234{
2235    // session not removed at kick and will removed in next update tick
2236  //TODO here
2237//    for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr)
2238//        if(WorldSession* session = (*itr)->GetSession())
2239//            session->KickPlayer();
2240
2241    m_QueuedPlayer.empty();
2242}
2243
2244/// Kick (and save) the designated player
2245bool World::KickPlayer(std::string playerName)
2246{
2247    SessionMap::iterator itr;
2248
2249    // session not removed at kick and will removed in next update tick
2250    for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2251    {
2252        if(!itr->second)
2253            continue;
2254        Player *player = itr->second->GetPlayer();
2255        if(!player)
2256            continue;
2257        if( player->IsInWorld() )
2258        {
2259            if (playerName == player->GetName())
2260            {
2261                itr->second->KickPlayer();
2262                return true;
2263            }
2264        }
2265    }
2266    return false;
2267}
2268
2269/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
2270BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
2271{
2272    loginDatabase.escape_string(nameOrIP);
2273    loginDatabase.escape_string(reason);
2274    std::string safe_author=author;
2275    loginDatabase.escape_string(safe_author);
2276
2277    uint32 duration_secs = TimeStringToSecs(duration);
2278    QueryResult *resultAccounts = NULL;                     //used for kicking
2279
2280    ///- Update the database with ban information
2281        switch(mode)
2282    {
2283        case BAN_IP:
2284                        //No SQL injection as strings are escaped
2285                        resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
2286                        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());
2287                        break;
2288                case BAN_ACCOUNT:
2289                        //No SQL injection as string is escaped
2290                        resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
2291                        break;
2292                case BAN_CHARACTER:
2293                        //No SQL injection as string is escaped
2294                        resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str());
2295                        break;
2296                default:
2297                        return BAN_SYNTAX_ERROR;
2298    }
2299   
2300        if(!resultAccounts)
2301        {
2302                if(mode==BAN_IP)
2303            return BAN_SUCCESS;
2304                else
2305                        return BAN_NOTFOUND;                                // Nobody to ban
2306        }
2307
2308    ///- Disconnect all affected players (for IP it can be several)
2309    do
2310    {
2311        Field* fieldsAccount = resultAccounts->Fetch();
2312        uint32 account = fieldsAccount->GetUInt32();
2313
2314        if(mode!=BAN_IP)
2315                {
2316            //No SQL injection as strings are escaped
2317            loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
2318                account,duration_secs,safe_author.c_str(),reason.c_str());
2319                }
2320
2321        if (WorldSession* sess = FindSession(account))
2322            if(std::string(sess->GetPlayerName()) != author)
2323                sess->KickPlayer();
2324    }
2325    while( resultAccounts->NextRow() );
2326
2327    delete resultAccounts;
2328    return BAN_SUCCESS;
2329}
2330
2331/// Remove a ban from an account or IP address
2332bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
2333{
2334    if (mode == BAN_IP)
2335    {
2336        loginDatabase.escape_string(nameOrIP);
2337        loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
2338    }
2339    else
2340    {
2341        uint32 account=0;
2342        if (mode == BAN_ACCOUNT)
2343            account = accmgr.GetId (nameOrIP);
2344        else if (mode == BAN_CHARACTER)
2345            account = objmgr.GetPlayerAccountIdByPlayerName (nameOrIP);
2346
2347        if(!account)
2348            return false;
2349           
2350        //NO SQL injection as account is uint32
2351        loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
2352    }
2353    return true;
2354}
2355
2356/// Update the game time
2357void World::_UpdateGameTime()
2358{
2359    ///- update the time
2360    time_t thisTime = time(NULL);
2361    uint32 elapsed = uint32(thisTime - m_gameTime);
2362    m_gameTime = thisTime;
2363
2364    ///- if there is a shutdown timer
2365    if(m_ShutdownTimer > 0 && elapsed > 0)
2366    {
2367        ///- ... and it is overdue, stop the world (set m_stopEvent)
2368        if( m_ShutdownTimer <= elapsed )
2369        {
2370            if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
2371                m_stopEvent = true;
2372            else
2373                m_ShutdownTimer = 1;                        // minimum timer value to wait idle state
2374        }
2375        ///- ... else decrease it and if necessary display a shutdown countdown to the users
2376        else
2377        {
2378            m_ShutdownTimer -= elapsed;
2379
2380            ShutdownMsg();
2381        }
2382    }
2383}
2384
2385/// Shutdown the server
2386void World::ShutdownServ(uint32 time, uint32 options)
2387{
2388    m_ShutdownMask = options;
2389
2390    ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions)
2391    if(time==0)
2392    {
2393        if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
2394            m_stopEvent = true;
2395        else
2396            m_ShutdownTimer = 1;                            //So that the session count is re-evaluated at next world tick
2397    }
2398    ///- Else set the shutdown timer and warn users
2399    else
2400    {
2401        m_ShutdownTimer = time;
2402        ShutdownMsg(true);
2403    }
2404}
2405
2406/// Display a shutdown message to the user(s)
2407void World::ShutdownMsg(bool show, Player* player)
2408{
2409    // not show messages for idle shutdown mode
2410    if(m_ShutdownMask & SHUTDOWN_MASK_IDLE)
2411        return;
2412
2413    ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
2414    if ( show ||
2415        (m_ShutdownTimer < 10) ||
2416                                                            // < 30 sec; every 5 sec
2417        (m_ShutdownTimer<30        && (m_ShutdownTimer % 5         )==0) ||
2418                                                            // < 5 min ; every 1 min
2419        (m_ShutdownTimer<5*MINUTE  && (m_ShutdownTimer % MINUTE    )==0) ||
2420                                                            // < 30 min ; every 5 min
2421        (m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) ||
2422                                                            // < 12 h ; every 1 h
2423        (m_ShutdownTimer<12*HOUR   && (m_ShutdownTimer % HOUR      )==0) ||
2424                                                            // > 12 h ; every 12 h
2425        (m_ShutdownTimer>12*HOUR   && (m_ShutdownTimer % (12*HOUR) )==0))
2426    {
2427        std::string str = secsToTimeString(m_ShutdownTimer);
2428
2429        uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
2430
2431        SendServerMessage(msgid,str.c_str(),player);
2432        outstring_log("Server will %s in %s", (m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutdown"), str.c_str());
2433    }
2434}
2435
2436/// Cancel a planned server shutdown
2437void World::ShutdownCancel()
2438{
2439    if(!m_ShutdownTimer)
2440        return;
2441
2442    uint32 msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
2443
2444    m_ShutdownMask = 0;
2445    m_ShutdownTimer = 0;
2446    SendServerMessage(msgid);
2447
2448    DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"));
2449}
2450
2451/// Send a server message to the user(s)
2452void World::SendServerMessage(uint32 type, const char *text, Player* player)
2453{
2454    WorldPacket data(SMSG_SERVER_MESSAGE, 50);              // guess size
2455    data << uint32(type);
2456    if(type <= SERVER_MSG_STRING)
2457        data << text;
2458
2459    if(player)
2460        player->GetSession()->SendPacket(&data);
2461    else
2462        SendGlobalMessage( &data );
2463}
2464
2465void World::UpdateSessions( time_t diff )
2466{
2467    while(!addSessQueue.empty())
2468    {
2469      WorldSession* sess = addSessQueue.next ();
2470      AddSession_ (sess);
2471    }
2472       
2473    ///- Delete kicked sessions at add new session
2474    for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr)
2475        delete *itr;
2476    m_kicked_sessions.clear();
2477
2478    ///- Then send an update signal to remaining ones
2479    for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
2480    {
2481        next = itr;
2482        ++next;
2483
2484        if(!itr->second)
2485            continue;
2486
2487        ///- and remove not active sessions from the list
2488        if(!itr->second->Update(diff))                      // As interval = 0
2489        {
2490            delete itr->second;
2491            m_sessions.erase(itr);
2492        }
2493    }
2494}
2495
2496// This handles the issued and queued CLI commands
2497void World::ProcessCliCommands()
2498{
2499    if (cliCmdQueue.empty())
2500                return;
2501
2502    CliCommandHolder::Print* zprint;
2503    while (!cliCmdQueue.empty())
2504    {
2505        sLog.outDebug("CLI command under processing...");
2506        CliCommandHolder *command = cliCmdQueue.next();
2507
2508                zprint = command->m_print;
2509
2510                CliHandler(zprint).ParseCommands(command->m_command);
2511
2512        delete command;
2513    }
2514
2515    // print the console message here so it looks right
2516    zprint("TC> ");
2517}
2518
2519void World::InitResultQueue()
2520{
2521    m_resultQueue = new SqlResultQueue;
2522    CharacterDatabase.SetResultQueue(m_resultQueue);
2523}
2524
2525void World::UpdateResultQueue()
2526{
2527    m_resultQueue->Update();
2528}
2529
2530void World::UpdateRealmCharCount(uint32 accountId)
2531{
2532    CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId,
2533        "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId);
2534}
2535
2536void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId)
2537{
2538    if (resultCharCount)
2539    {
2540        Field *fields = resultCharCount->Fetch();
2541        uint32 charCount = fields[0].GetUInt32();
2542        delete resultCharCount;
2543        loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
2544        loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
2545    }
2546}
2547
2548void World::InitDailyQuestResetTime()
2549{
2550    time_t mostRecentQuestTime;
2551
2552    QueryResult* result = CharacterDatabase.Query("SELECT MAX(time) FROM character_queststatus_daily");
2553    if(result)
2554    {
2555        Field *fields = result->Fetch();
2556
2557        mostRecentQuestTime = (time_t)fields[0].GetUInt64();
2558        delete result;
2559    }
2560    else
2561        mostRecentQuestTime = 0;
2562
2563    // client built-in time for reset is 6:00 AM
2564    // FIX ME: client not show day start time
2565    time_t curTime = time(NULL);
2566    tm localTm = *localtime(&curTime);
2567    localTm.tm_hour = 6;
2568    localTm.tm_min  = 0;
2569    localTm.tm_sec  = 0;
2570
2571    // current day reset time
2572    time_t curDayResetTime = mktime(&localTm);
2573
2574    // last reset time before current moment
2575    time_t resetTime = (curTime < curDayResetTime) ? curDayResetTime - DAY : curDayResetTime;
2576
2577    // need reset (if we have quest time before last reset time (not processed by some reason)
2578    if(mostRecentQuestTime && mostRecentQuestTime <= resetTime)
2579        m_NextDailyQuestReset = mostRecentQuestTime;
2580    else
2581    {
2582        // plan next reset time
2583        m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + DAY : curDayResetTime;
2584    }
2585}
2586
2587void World::ResetDailyQuests()
2588{
2589    sLog.outDetail("Daily quests reset for all characters.");
2590    CharacterDatabase.Execute("DELETE FROM character_queststatus_daily");
2591    for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
2592        if(itr->second->GetPlayer())
2593            itr->second->GetPlayer()->ResetDailyQuestStatus();
2594}
2595
2596void World::SetPlayerLimit( int32 limit, bool needUpdate )
2597{
2598    if(limit < -SEC_ADMINISTRATOR)
2599        limit = -SEC_ADMINISTRATOR;
2600
2601    // lock update need
2602    bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit);
2603
2604    m_playerLimit = limit;
2605
2606    if(db_update_need)
2607        loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
2608}
2609
2610void World::UpdateMaxSessionCounters()
2611{
2612    m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size()));
2613    m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size()));
2614}
Note: See TracBrowser for help on using the browser.