aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormegamage <none@none>2009-01-04 16:17:46 -0600
committermegamage <none@none>2009-01-04 16:17:46 -0600
commiteb5a7b02eef6fe13684dfe14faf048bbce1d0f83 (patch)
tree395bd3da004c0628956d64335ee0e2c404d4f772 /src
parent820e0214faf4645ef1bc411aa5cc581392db62db (diff)
parent15d25f45ae920a4418f3fcb1e6828c923a3aedc1 (diff)
*Merge with Trinity 783.
--HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/bindings/scripts/Makefile.am1
-rw-r--r--src/bindings/scripts/ScriptMgr.cpp4
-rw-r--r--src/bindings/scripts/VC71/71ScriptDev2.vcproj4
-rw-r--r--src/bindings/scripts/VC80/80ScriptDev2.vcproj4
-rw-r--r--src/bindings/scripts/VC90/90ScriptDev2.vcproj4
-rw-r--r--src/bindings/scripts/include/sc_creature.cpp3
-rw-r--r--src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp350
-rw-r--r--src/bindings/scripts/scripts/zone/thousand_needles/thousand_needles.cpp200
-rw-r--r--src/game/AccountMgr.cpp50
-rw-r--r--src/game/CharacterHandler.cpp10
-rw-r--r--src/game/Chat.cpp2
-rw-r--r--src/game/Level0.cpp6
-rw-r--r--src/game/Level1.cpp82
-rw-r--r--src/game/Level2.cpp18
-rw-r--r--src/game/Level3.cpp38
-rw-r--r--src/game/MiscHandler.cpp2
-rw-r--r--src/game/PetAI.cpp3
-rw-r--r--src/game/Player.cpp20
-rw-r--r--src/game/Spell.cpp26
-rw-r--r--src/game/SpellAuras.cpp3
-rw-r--r--src/game/TicketHandler.cpp12
-rw-r--r--src/game/TicketMgr.cpp40
-rw-r--r--src/game/TicketMgr.h20
-rw-r--r--src/game/Unit.cpp58
-rw-r--r--src/game/Unit.h2
-rw-r--r--src/game/World.cpp32
-rw-r--r--src/game/WorldSession.cpp2
-rw-r--r--src/game/WorldSocket.cpp12
-rw-r--r--src/shared/Database/DatabaseEnv.h2
-rw-r--r--src/trinitycore/CliRunnable.cpp2
-rw-r--r--src/trinitycore/Main.cpp165
-rw-r--r--src/trinitycore/Master.cpp517
-rw-r--r--src/trinitycore/RASocket.cpp259
-rw-r--r--src/trinityrealm/AuthSocket.cpp1094
-rw-r--r--src/trinityrealm/Main.cpp345
-rw-r--r--src/trinityrealm/RealmList.cpp102
36 files changed, 3079 insertions, 415 deletions
diff --git a/src/bindings/scripts/Makefile.am b/src/bindings/scripts/Makefile.am
index 34ef03bb3e0..74e1674619a 100644
--- a/src/bindings/scripts/Makefile.am
+++ b/src/bindings/scripts/Makefile.am
@@ -375,6 +375,7 @@ scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp \
scripts/zone/terokkar_forest/terokkar_forest.cpp \
scripts/zone/thunder_bluff/thunder_bluff.cpp \
scripts/zone/tirisfal_glades/tirisfal_glades.cpp \
+scripts/zone/thousand_needles/thousand_needles.cpp \
scripts/zone/uldaman/boss_archaedas.cpp \
scripts/zone/uldaman/instance_uldaman.cpp \
scripts/zone/uldaman/boss_ironaya.cpp \
diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp
index 9024498d00b..d28a17b9104 100644
--- a/src/bindings/scripts/ScriptMgr.cpp
+++ b/src/bindings/scripts/ScriptMgr.cpp
@@ -545,6 +545,8 @@ extern void AddSC_instance_temple_of_ahnqiraj();
extern void AddSC_terokkar_forest();
//Thousand Needles
+extern void AddSC_thousand_needles();
+
//Thunder Bluff
extern void AddSC_thunder_bluff();
@@ -1749,6 +1751,8 @@ void ScriptsInit()
AddSC_terokkar_forest();
//Thousand Needles
+ AddSC_thousand_needles();
+
//Thunder Bluff
AddSC_thunder_bluff();
diff --git a/src/bindings/scripts/VC71/71ScriptDev2.vcproj b/src/bindings/scripts/VC71/71ScriptDev2.vcproj
index bb84b59dad5..a9ed124ebec 100644
--- a/src/bindings/scripts/VC71/71ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC71/71ScriptDev2.vcproj
@@ -1072,6 +1072,10 @@
<Filter
Name="Thousand Needles"
>
+ <File
+ RelativePath="..\scripts\zone\thousand_needles\thousand_needles.cpp"
+ >
+ </File>
</Filter>
<Filter
Name="Silithus"
diff --git a/src/bindings/scripts/VC80/80ScriptDev2.vcproj b/src/bindings/scripts/VC80/80ScriptDev2.vcproj
index d6123c0ef43..5d84995e2ed 100644
--- a/src/bindings/scripts/VC80/80ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC80/80ScriptDev2.vcproj
@@ -1334,6 +1334,10 @@
<Filter
Name="Thousand Needles"
>
+ <File
+ RelativePath="..\scripts\zone\thousand_needles\thousand_needles.cpp"
+ >
+ </File>
</Filter>
<Filter
Name="Silithus"
diff --git a/src/bindings/scripts/VC90/90ScriptDev2.vcproj b/src/bindings/scripts/VC90/90ScriptDev2.vcproj
index f325a567d13..635c7c67bf9 100644
--- a/src/bindings/scripts/VC90/90ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC90/90ScriptDev2.vcproj
@@ -1354,6 +1354,10 @@
<Filter
Name="Thousand Needles"
>
+ <File
+ RelativePath="..\scripts\zone\thousand_needles\thousand_needles.cpp"
+ >
+ </File>
</Filter>
<Filter
Name="Silithus"
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp
index b54f91a113d..bb7f98c9f7b 100644
--- a/src/bindings/scripts/include/sc_creature.cpp
+++ b/src/bindings/scripts/include/sc_creature.cpp
@@ -432,7 +432,7 @@ void ScriptedAI::SelectUnitList(std::list<Unit*> &targetList, uint32 num, Select
std::list<HostilReference*> m_threatlist = m_creature->getThreatManager().getThreatList();
std::list<HostilReference*>::iterator i;
Unit *target;
- while(m_threatlist.size())
+ while(m_threatlist.size() && num)
{
if(targetType == SELECT_TARGET_BOTTOMAGGRO)
{
@@ -455,6 +455,7 @@ void ScriptedAI::SelectUnitList(std::list<Unit*> &targetList, uint32 num, Select
continue;
}
targetList.push_back(target);
+ --num;
}
}
}
diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
index 06947376619..35f1cffa8e8 100644
--- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
+++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -36,22 +36,20 @@ EndScriptData */
#define SPELL_RAIN_OF_FIRE 33617
#define H_SPELL_RAIN_OF_FIRE 39363
-#define SPELL_DRAWN_SHADOWS 33563
+#define SPELL_DRAW_SHADOWS 33563
#define SPELL_SHADOWBOLT_VOLLEY 33841
+#define SPELL_BANISH 38791
#define MOB_VOID_TRAVELER 19226
#define SPELL_SACRIFICE 33587
#define SPELL_SHADOW_NOVA 33846
-#define SPELL_HEALVORPIL 33783
-#define H_SPELL_HEALVORPIL 39364
+#define SPELL_EMPOWERING_SHADOWS 33783
+#define H_SPELL_EMPOWERING_SHADOWS 39364
#define MOB_VOID_PORTAL 19224
#define SPELL_VOID_PORTAL_VISUAL 33569
-float VorpilPosition[1][3] =
-{
- {-252.8820,-264.3030,17.1}
-};
+float VorpilPosition[3] = {-252.8820,-264.3030,17.1};
float VoidPortalCoords[5][3] =
{
@@ -62,76 +60,154 @@ float VoidPortalCoords[5][3] =
{-261.4533, -297.3298, 17.1}
};
+class EmpoweringShadowsAura: public Aura
+{
+ public:
+ EmpoweringShadowsAura(SpellEntry *spell, uint32 eff, int32 *bp, Unit *target, Unit *caster) : Aura(spell, eff, bp, target, caster, NULL) {}
+};
+
+struct TRINITY_DLL_DECL mob_voidtravelerAI : public ScriptedAI
+{
+ mob_voidtravelerAI(Creature *c) : ScriptedAI(c)
+ {
+ HeroicMode = m_creature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ bool HeroicMode;
+ Unit *Vorpil;
+ uint32 move;
+ bool sacrificed;
+
+ void Reset()
+ {
+ Vorpil = NULL;
+ move = 0;
+ sacrificed = false;
+ }
+
+ void Aggro(Unit *who){}
+
+ void UpdateAI(const uint32 diff)
+ {
+ if(!Vorpil)
+ {
+ m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ return;
+ }
+ if(move < diff)
+ {
+ if(sacrificed)
+ {
+ SpellEntry *spell = (SpellEntry *)GetSpellStore()->LookupEntry(HeroicMode?H_SPELL_EMPOWERING_SHADOWS:SPELL_EMPOWERING_SHADOWS);
+ if( spell )
+ Vorpil->AddAura(new EmpoweringShadowsAura(spell, 0, NULL, Vorpil, m_creature));
+ Vorpil->SetHealth(Vorpil->GetHealth()+Vorpil->GetMaxHealth()/25);
+ DoCast(m_creature, SPELL_SHADOW_NOVA, true);
+ m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ return;
+ }
+ m_creature->GetMotionMaster()->MoveFollow(Vorpil,0,0);
+ if(m_creature->GetDistance(Vorpil) < 3)
+ {
+ DoCast(m_creature, SPELL_SACRIFICE, false);
+ sacrificed = true;
+ move = 500;
+ return;
+ }
+ if(!Vorpil->isInCombat() || Vorpil->isDead())
+ {
+ m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ return;
+ }
+ move = 1000;
+ }else move -= diff;
+ }
+};
+CreatureAI* GetAI_mob_voidtraveler(Creature *_Creature)
+{
+ return new mob_voidtravelerAI (_Creature);
+}
+
struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI
{
boss_grandmaster_vorpilAI(Creature *c) : ScriptedAI(c)
{
pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ HeroicMode = m_creature->GetMap()->IsHeroic();
Intro = false;
Reset();
}
ScriptedInstance *pInstance;
- bool Intro;
+ bool Intro, HelpYell;
bool sumportals;
bool HeroicMode;
uint32 ShadowBoltVolley_Timer;
- uint32 DrawnShadows_Timer;
- uint32 sumportals_Timer;
+ uint32 DrawShadows_Timer;
uint32 summonTraveler_Timer;
- uint64 PortalsGuid[5];
+ uint32 banish_Timer;
+ uint64 PortalsGuid[5];
+
+ void Reset()
+ {
+ ShadowBoltVolley_Timer = 15000;
+ DrawShadows_Timer = 45000;
+ summonTraveler_Timer = 90000;
+ banish_Timer = 17000;
+ HelpYell = false;
+ destroyPortals();
+ if(pInstance)
+ pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, NOT_STARTED);
+ }
void summonPortals()
{
- for (int i = 0;i<5;i++)
+ if(!sumportals)
{
- Creature *Portal = NULL;
- Portal = m_creature->SummonCreature(MOB_VOID_PORTAL,VoidPortalCoords[i][0],VoidPortalCoords[i][1],VoidPortalCoords[i][2],0,TEMPSUMMON_CORPSE_DESPAWN,3000000);
- PortalsGuid[i] = Portal->GetGUID();
- Portal->CastSpell(Portal,SPELL_VOID_PORTAL_VISUAL,false);
+ for (int i = 0;i<5;i++)
+ {
+ Creature *Portal = NULL;
+ Portal = m_creature->SummonCreature(MOB_VOID_PORTAL,VoidPortalCoords[i][0],VoidPortalCoords[i][1],VoidPortalCoords[i][2],0,TEMPSUMMON_CORPSE_DESPAWN,3000000);
+ PortalsGuid[i] = Portal->GetGUID();
+ Portal->CastSpell(Portal,SPELL_VOID_PORTAL_VISUAL,false);
+ }
+ sumportals = true;
+ summonTraveler_Timer = 5000;
}
- sumportals = true;
- summonTraveler_Timer = 5000;
}
void destroyPortals()
{
- for (int i = 0;i < 5; i ++)
+ if(sumportals)
{
- Unit *Portal = Unit::GetUnit((*m_creature), PortalsGuid[i]);
- if (Portal)
- if (Portal->isAlive())
+ for (int i = 0;i < 5; i ++)
+ {
+ Unit *Portal = Unit::GetUnit((*m_creature), PortalsGuid[i]);
+ if (Portal && Portal->isAlive())
Portal->DealDamage(Portal, Portal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- PortalsGuid[i] = 0;
- }
+ PortalsGuid[i] = 0;
+ }
+ sumportals = false;
+ }
}
void spawnVoidTraveler()
{
- srand( (unsigned) time(NULL) ) ;
int pos = rand()%5;
- Creature *traveler;
- traveler = m_creature->SummonCreature(MOB_VOID_TRAVELER,VoidPortalCoords[pos][0],VoidPortalCoords[pos][1],VoidPortalCoords[pos][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000);
+ m_creature->SummonCreature(MOB_VOID_TRAVELER,VoidPortalCoords[pos][0],VoidPortalCoords[pos][1],VoidPortalCoords[pos][2],0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,5000);
+ if(!HelpYell)
+ {
+ DoScriptText(SAY_HELP, m_creature);
+ HelpYell = true;
+ }
}
- void Reset()
+ void JustSummoned(Creature *summoned)
{
- HeroicMode = m_creature->GetMap()->IsHeroic();
- if( HeroicMode )
- debug_log("SD2: creature %u is in heroic mode",m_creature->GetEntry());
-
- ShadowBoltVolley_Timer = 15000;
- DrawnShadows_Timer = 45000;
- sumportals_Timer = 10000;
- summonTraveler_Timer = 90000;
-
- InCombat = false;
- sumportals = false;
- destroyPortals();
-
- if(pInstance)
- pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, NOT_STARTED);
+ if (summoned && summoned->GetEntry() == MOB_VOID_TRAVELER)
+ ((mob_voidtravelerAI*)summoned->AI())->Vorpil = m_creature;
}
void KilledUnit(Unit *victim)
@@ -151,7 +227,7 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI
pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, DONE);
}
- void StartEvent()
+ void Aggro(Unit *who)
{
switch(rand()%3)
{
@@ -159,55 +235,27 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI
case 1: DoScriptText(SAY_AGGRO2, m_creature); break;
case 2: DoScriptText(SAY_AGGRO3, m_creature); break;
}
-
+ summonPortals();
if(pInstance)
pInstance->SetData(DATA_GRANDMASTERVORPILEVENT, IN_PROGRESS);
}
- void Aggro(Unit *who)
- {
- if(!InCombat)
- {
- InCombat = true;
- StartEvent();
- }
- }
-
void MoveInLineOfSight(Unit *who)
{
- if (!who || m_creature->getVictim())
- return;
-
- if (who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
- {
- AttackStart(who);
- }
- }
- else if (!Intro && m_creature->IsWithinLOSInMap(who)&& m_creature->IsWithinDistInMap(who, 100) ) //not sure about right radius
+ if(who && !m_creature->getVictim() && m_creature->canStartAttack(who))
+ AttackStart(who);
+ if (!Intro && who && m_creature->IsWithinLOSInMap(who)&& m_creature->IsWithinDistInMap(who, 100) && m_creature->IsHostileTo(who))
{
DoScriptText(SAY_INTRO, m_creature);
Intro = true;
}
-
}
-
+
void UpdateAI(const uint32 diff)
{
if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
-
- if (!sumportals)
- if (sumportals_Timer < diff)
- {
- DoScriptText(SAY_HELP, m_creature);
- summonPortals();
- sumportals_Timer = 1000000;
-
- }else sumportals_Timer -= diff;
if (ShadowBoltVolley_Timer < diff)
{
@@ -215,23 +263,41 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI
ShadowBoltVolley_Timer = 15000;
}else ShadowBoltVolley_Timer -= diff;
- if ( DrawnShadows_Timer < diff)
+ if (HeroicMode && banish_Timer < diff)
+ {
+ Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0,30,false);
+ if (target)
+ {
+ DoCast(target,SPELL_BANISH);
+ banish_Timer = 16000;
+ }
+ }else banish_Timer -= diff;
+
+ if ( DrawShadows_Timer < diff)
{
- DoTeleportAll(VorpilPosition[0][0],VorpilPosition[0][1],VorpilPosition[0][2],0);
- m_creature->Relocate(VorpilPosition[0][0],VorpilPosition[0][1],VorpilPosition[0][2],0);
- DoCast(m_creature,SPELL_DRAWN_SHADOWS,true);
+ Map *map = m_creature->GetMap();
+ Map::PlayerList const &PlayerList = map->GetPlayers();
+ for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
+ if (Player* i_pl = i->getSource())
+ if (i_pl->isAlive() && !i_pl->HasAura(SPELL_BANISH,0))
+ i_pl->TeleportTo(m_creature->GetMapId(), VorpilPosition[0],VorpilPosition[1],VorpilPosition[2], 0, TELE_TO_NOT_LEAVE_COMBAT);
- if(!HeroicMode) DoCast(m_creature,SPELL_RAIN_OF_FIRE);
- else DoCast(m_creature,H_SPELL_RAIN_OF_FIRE);
+ m_creature->Relocate(VorpilPosition[0],VorpilPosition[1],VorpilPosition[2]);
+ DoCast(m_creature,SPELL_DRAW_SHADOWS,true);
+
+ DoCast(m_creature,HeroicMode?H_SPELL_RAIN_OF_FIRE:SPELL_RAIN_OF_FIRE);
ShadowBoltVolley_Timer = 6000;
- DrawnShadows_Timer = 45000;
- }else DrawnShadows_Timer -= diff;
+ DrawShadows_Timer = 30000;
+ }else DrawShadows_Timer -= diff;
if ( summonTraveler_Timer < diff)
{
spawnVoidTraveler();
summonTraveler_Timer = 10000;
+ //enrage at 20%
+ if((m_creature->GetHealth()*5) < m_creature->GetMaxHealth())
+ summonTraveler_Timer = 5000;
}else summonTraveler_Timer -=diff;
DoMeleeAttackIfReady();
@@ -242,118 +308,6 @@ CreatureAI* GetAI_boss_grandmaster_vorpil(Creature *_Creature)
return new boss_grandmaster_vorpilAI (_Creature);
}
-struct TRINITY_DLL_DECL mob_voidtravelerAI : public ScriptedAI
-{
- mob_voidtravelerAI(Creature *c) : ScriptedAI(c)
- {
- pInstance = ((ScriptedInstance*)c->GetInstanceData());
- Reset();
- }
-
- ScriptedInstance *pInstance;
- uint32 VorpilCheck_Timer;
- uint32 eventCheck_Timer;
- bool sacrifice;
- bool sacrificed;
- bool oneTarget;
- bool HeroicMode;
-
- uint32 target_timer;
-
- void Reset()
- {
- HeroicMode = m_creature->GetMap()->IsHeroic();
- if( HeroicMode )
- debug_log("SD2: creature %u is in heroic mode",m_creature->GetEntry());
-
- VorpilCheck_Timer = 5000;
- eventCheck_Timer = 1000;
- target_timer = 2000;
- oneTarget = false;
- sacrificed = false;
- sacrifice = false;
- }
- void EnterEvadeMode(){}
- void Aggro(Unit *who) {}
- void AttackStart(Unit *who){}
- void MoveInLineOfSight(Unit *who){}
-
- void UpdateAI(const uint32 diff)
- {
- if (eventCheck_Timer < diff)
- {
- if(pInstance)
- {
- Unit *Vorpil = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_GRANDMASTERVORPIL));
- if (Vorpil)
- {
- if (Vorpil->isDead())
- {
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
-
- if (Vorpil->getVictim())
- {
- if((*m_creature).GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
- (*m_creature).GetMotionMaster()->MoveFollow(Vorpil,1,0);
- }
- }
- if(pInstance->GetData(DATA_GRANDMASTERVORPILEVENT) != IN_PROGRESS)
- {
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- }
- }
- eventCheck_Timer = 5000;
- }else eventCheck_Timer -=diff;
-
- if (VorpilCheck_Timer < diff)
- {
- if (pInstance)
- {
- if (!sacrificed)
- {
- if (!sacrifice)
- {
- Unit *Vorpil = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_GRANDMASTERVORPIL));
- if (Vorpil)
- if (Vorpil->isAlive())
- {
- if (m_creature->IsWithinDistInMap(Vorpil, 2))
- {
- sacrifice = true;
- DoCast(m_creature,SPELL_SACRIFICE);
- VorpilCheck_Timer = 2000;
- }
- }
-
- if (!sacrifice)
- VorpilCheck_Timer = 3000;
- }
- else
- {
- Unit *Vorpil = Unit::GetUnit((*m_creature),pInstance->GetData64(DATA_GRANDMASTERVORPIL));
- if (Vorpil)
- if (Vorpil->isAlive())
- {
- if(!HeroicMode) Vorpil->CastSpell(Vorpil,SPELL_HEALVORPIL,true);
- else Vorpil->CastSpell(Vorpil,H_SPELL_HEALVORPIL,true);
- };
- DoCast(m_creature,SPELL_SHADOW_NOVA);
- sacrificed = true;
- m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- VorpilCheck_Timer = 100000;
- }
- }
- }
- }else VorpilCheck_Timer -= diff;
- }
-};
-
-CreatureAI* GetAI_mob_voidtraveler(Creature *_Creature)
-{
- return new mob_voidtravelerAI (_Creature);
-}
-
void AddSC_boss_grandmaster_vorpil()
{
Script *newscript;
diff --git a/src/bindings/scripts/scripts/zone/thousand_needles/thousand_needles.cpp b/src/bindings/scripts/scripts/zone/thousand_needles/thousand_needles.cpp
new file mode 100644
index 00000000000..6d230a49e3b
--- /dev/null
+++ b/src/bindings/scripts/scripts/zone/thousand_needles/thousand_needles.cpp
@@ -0,0 +1,200 @@
+/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* ScriptData
+SDName: Thousand Needles
+SD%Complete: 100
+SDComment: Support for Quest: 4770
+SDCategory: Thousand Needles
+EndScriptData */
+
+/* ContentData
+npc_swiftmountain
+EndContentData */
+
+#include "precompiled.h"
+#include "../../npc/npc_escortAI.h"
+
+#define SAY_READY -1000147
+#define SAY_AGGRO -1000148
+#define SAY_FINISH -1000149
+
+#define QUEST_HOMEWARD_BOUND 4770
+#define ENTRY_WYVERN 4107
+
+
+
+struct TRINITY_DLL_DECL npc_swiftmountainAI : public npc_escortAI
+{
+npc_swiftmountainAI(Creature *c) : npc_escortAI(c) {Reset();}
+
+ void WaypointReached(uint32 i)
+ {
+ Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
+
+ if (!player)
+ return;
+
+ switch (i)
+ {
+ case 46:
+ DoScriptText(SAY_AGGRO, m_creature, player);
+ break;
+ case 47:
+ m_creature->SummonCreature(ENTRY_WYVERN, -5016.45, -935.01, -5.46, 5.36,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
+ m_creature->SummonCreature(ENTRY_WYVERN, -5001.98, -934.96, -5.55, 3.18,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
+ m_creature->SummonCreature(ENTRY_WYVERN, -4999.06, -949.61, -5.42, 2.04,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
+ break;
+ case 70:
+ DoScriptText(SAY_FINISH, m_creature, player);
+ if (player && player->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)player)->GroupEventHappens(QUEST_HOMEWARD_BOUND,m_creature);
+ break;
+
+ }
+ }
+
+ void Reset()
+ {
+
+ }
+
+ void Aggro(Unit* who)
+ {}
+
+ void JustSummoned(Creature* summoned)
+ {
+ summoned->AI()->AttackStart(m_creature);
+ }
+
+ void JustDied(Unit* killer)
+ {
+ if (PlayerGUID)
+ {
+ if (Unit* player = Unit::GetUnit((*m_creature), PlayerGUID))
+ ((Player*)player)->FailQuest(QUEST_HOMEWARD_BOUND);
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ npc_escortAI::UpdateAI(diff);
+ }
+};
+
+bool QuestAccept_npc_swiftmountain(Player* player, Creature* creature, Quest const* quest)
+{
+ if (quest->GetQuestId() == QUEST_HOMEWARD_BOUND)
+ {
+ ((npc_escortAI*)(creature->AI()))->Start(true, true, false, player->GetGUID());
+ DoScriptText(SAY_READY, creature, player);
+ // Change faction so mobs attack
+ creature->setFaction(775);
+ }
+
+ return true;
+}
+
+CreatureAI* GetAI_npc_swiftmountain(Creature *_Creature)
+{
+ npc_swiftmountainAI* thisAI = new npc_swiftmountainAI(_Creature);
+
+ thisAI->AddWaypoint(0, -5156.69, -1220.49, 48.78, 5000);
+ thisAI->AddWaypoint(1, -5157.12, -1220.13, 48.67);
+ thisAI->AddWaypoint(2, -5171.7, -1205.36, 47.43);
+ thisAI->AddWaypoint(3, -5174.08, -1197.7, 46.90);
+ thisAI->AddWaypoint(4, -5178.24, -1183.78, 45.97);
+ thisAI->AddWaypoint(5, -5181.52, -1171.03, 45.29);
+ thisAI->AddWaypoint(6, -5184.29, -1159.21, 44.62);
+ thisAI->AddWaypoint(7, -5184.84, -1152.95, 44.84);
+ thisAI->AddWaypoint(8, -5182.04, -1142.83, 44.07);
+ thisAI->AddWaypoint(9, -5178.44, -1133.57, 43.91);
+ thisAI->AddWaypoint(10, -5176.68, -1129.48, 43.81);
+ thisAI->AddWaypoint(11, -5164.85, -1123.33, 43.99);
+ thisAI->AddWaypoint(12, -5153.07, -1117.7, 43.66);
+ thisAI->AddWaypoint(13, -5143.52, -1113.14, 43.78);
+ thisAI->AddWaypoint(14, -5135.86, -1104.42, 47.23);
+ thisAI->AddWaypoint(15, -5129.86, -1097.22, 49.52);
+ thisAI->AddWaypoint(16, -5127.48, -1087.29, 49.03);
+ thisAI->AddWaypoint(17, -5127.57, -1080.4, 46.64);
+ thisAI->AddWaypoint(18, -5129.65, -1077.58, 45.29);
+ thisAI->AddWaypoint(19, -5135.86, -1069.12, 39.53);
+ thisAI->AddWaypoint(20, -5141.97, -1060.58, 32.70);
+ thisAI->AddWaypoint(21, -5145.99, -1054.85, 28.98);
+ thisAI->AddWaypoint(22, -5147.08, -1050.35, 26.36);
+ thisAI->AddWaypoint(23, -5147.5, -1043.37, 21.84);
+ thisAI->AddWaypoint(24, -5147.68, -1036.37, 17.05);
+ thisAI->AddWaypoint(25, -5147.68, -1029.37, 14.59);
+ thisAI->AddWaypoint(26, -5144.62, -1023.9, 11.67);
+ thisAI->AddWaypoint(27, -5138.67, -1020.23, 7.81);
+ thisAI->AddWaypoint(28, -5135.6, -1018.55, 6.19);
+ thisAI->AddWaypoint(29, -5126.25, -1014.76, 1.08);
+ thisAI->AddWaypoint(30, -5120.03, -1013.12, -1.11);
+ thisAI->AddWaypoint(31, -5112.3, -1027.65, -5.39);
+ thisAI->AddWaypoint(32, -5106.99, -1023.09, -5.10);
+ thisAI->AddWaypoint(33, -5099.07, -1016.19, -4.92);
+ thisAI->AddWaypoint(34, -5091.23, -1009.21, -5.22);
+ thisAI->AddWaypoint(35, -5083.62, -1001.97, -5.22);
+ thisAI->AddWaypoint(36, -5076.1, -994.652, -4.92);
+ thisAI->AddWaypoint(37, -5066.71, -985.507, -4.97);
+ thisAI->AddWaypoint(38, -5065.13, -978.689, -5.02);
+ thisAI->AddWaypoint(39, -5062.33, -968.57, -5.08);
+ thisAI->AddWaypoint(40, -5059.46, -958.469, -5.16);
+ thisAI->AddWaypoint(41, -5056.59, -948.375, -5.10);
+ thisAI->AddWaypoint(42, -5053.73, -938.274, -5.69);
+ thisAI->AddWaypoint(43, -5043.06, -934.822, -5.35);
+ thisAI->AddWaypoint(44, -5029.35, -932.007, -5.27);
+ thisAI->AddWaypoint(45, -5024.58, -933.781, -5.40);
+ thisAI->AddWaypoint(46, -5019.13, -938.172, -5.54);
+ thisAI->AddWaypoint(47, -5011, -944.812, -5.47);
+ thisAI->AddWaypoint(48, -5002.86, -951.455, -5.44);
+ thisAI->AddWaypoint(49, -4994.73, -958.099, -5.41);
+ thisAI->AddWaypoint(50, -4990.57, -963.782, -5.33);
+ thisAI->AddWaypoint(51, -4987.43, -970.041, -5.17);
+ thisAI->AddWaypoint(52, -4981.41, -982.678, -5.10);
+ thisAI->AddWaypoint(53, -4977.03, -992.221, -4.97);
+ thisAI->AddWaypoint(54, -4972.6, -1001.74, -5.24);
+ thisAI->AddWaypoint(55, -4968.15, -1011.25, -5.49);
+ thisAI->AddWaypoint(56, -4963.75, -1020.78, -5.07);
+ thisAI->AddWaypoint(57, -4959.3, -1030.3, -5.28);
+ thisAI->AddWaypoint(58, -4956.28, -1036.61, -5.84);
+ thisAI->AddWaypoint(59, -4952.05, -1043.75, -9.04);
+ thisAI->AddWaypoint(60, -4943.8, -1055.06, -17.91);
+ thisAI->AddWaypoint(61, -4939.47, -1055.61, -20.73);
+ thisAI->AddWaypoint(62, -4929.16, -1053.64, -25.65);
+ thisAI->AddWaypoint(63, -4922.28, -1052.37, -28.72);
+ thisAI->AddWaypoint(64, -4913.26, -1051.3, -31.80);
+ thisAI->AddWaypoint(65, -4903.54, -1054.17, -33.48);
+ thisAI->AddWaypoint(66, -4905.95, -1056.71, -33.68);
+ thisAI->AddWaypoint(67, -4913.18, -1064.32, -39.46);
+ thisAI->AddWaypoint(68, -4925.27, -1076.98, -47.39);
+ thisAI->AddWaypoint(69, -4932.68, -1084.42, -51.00);
+ thisAI->AddWaypoint(70, -4938.3, -1100.41, -50.71, 5000);
+ thisAI->AddWaypoint(71, -4937.34, -1102.87, -49.82);
+
+ return (CreatureAI*)thisAI;
+}
+
+void AddSC_thousand_needles()
+{
+ Script *newscript;
+
+ newscript = new Script;
+ newscript->Name = "npc_swiftmountain";
+ newscript->GetAI = &GetAI_npc_swiftmountain;
+ newscript->pQuestAccept = &QuestAccept_npc_swiftmountain;
+ newscript->RegisterSelf();
+} \ No newline at end of file
diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp
index dedc1150ba4..adf47f8acab 100644
--- a/src/game/AccountMgr.cpp
+++ b/src/game/AccountMgr.cpp
@@ -26,9 +26,9 @@
#include "Util.h"
#ifdef DO_POSTGRESQL
-extern DatabasePostgre loginDatabase;
+extern DatabasePostgre LoginDatabase;
#else
-extern DatabaseMysql loginDatabase;
+extern DatabaseMysql LoginDatabase;
#endif
INSTANTIATE_SINGLETON_1(AccountMgr);
@@ -47,26 +47,26 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
normilizeString(username);
normilizeString(password);
- loginDatabase.escape_string(username);
- loginDatabase.escape_string(password);
+ LoginDatabase.escape_string(username);
+ LoginDatabase.escape_string(password);
- QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str());
+ QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'", username.c_str());
if(result)
{
delete result;
return AOR_NAME_ALREDY_EXIST; // username does already exist
}
- if(!loginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str()))
+ if(!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s',SHA1(CONCAT('%s',':','%s')),NOW())", username.c_str(), username.c_str(), password.c_str()))
return AOR_DB_INTERNAL_ERROR; // unexpected error
- loginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
+ LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
return AOR_OK; // everything's fine
}
AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
{
- QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -97,13 +97,13 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
// table realm specific but common for all characters of account for realm
CharacterDatabase.PExecute("DELETE FROM character_tutorial WHERE account = '%u'",accid);
- loginDatabase.BeginTransaction();
+ LoginDatabase.BeginTransaction();
bool res =
- loginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
- loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
+ LoginDatabase.PExecute("DELETE FROM account WHERE id='%d'", accid) &&
+ LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid='%d'", accid);
- loginDatabase.CommitTransaction();
+ LoginDatabase.CommitTransaction();
if(!res)
return AOR_DB_INTERNAL_ERROR; // unexpected error;
@@ -113,7 +113,7 @@ AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd)
{
- QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -127,9 +127,9 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
normilizeString(new_uname);
normilizeString(new_passwd);
- loginDatabase.escape_string(new_uname);
- loginDatabase.escape_string(new_passwd);
- if(!loginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid))
+ LoginDatabase.escape_string(new_uname);
+ LoginDatabase.escape_string(new_passwd);
+ if(!LoginDatabase.PExecute("UPDATE account SET username='%s',sha_pass_hash=SHA1(CONCAT('%s',':','%s')) WHERE id='%d'", new_uname.c_str(), new_uname.c_str(), new_passwd.c_str(), accid))
return AOR_DB_INTERNAL_ERROR; // unexpected error
return AOR_OK;
@@ -137,7 +137,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accid, std::string new_uname,
AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
{
- QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
+ QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d'", accid);
if(!result)
return AOR_NAME_NOT_EXIST; // account doesn't exist
delete result;
@@ -147,8 +147,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
normilizeString(new_passwd);
- loginDatabase.escape_string(new_passwd);
- if(!loginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
+ LoginDatabase.escape_string(new_passwd);
+ if(!LoginDatabase.PExecute("UPDATE account SET sha_pass_hash=SHA1(CONCAT(username,':','%s')) WHERE id='%d'", new_passwd.c_str(), accid))
return AOR_DB_INTERNAL_ERROR; // unexpected error
return AOR_OK;
@@ -156,8 +156,8 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accid, std::string new_passwd)
uint32 AccountMgr::GetId(std::string username)
{
- loginDatabase.escape_string(username);
- QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str());
+ LoginDatabase.escape_string(username);
+ QueryResult *result = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'", username.c_str());
if(!result)
return 0;
else
@@ -170,7 +170,7 @@ uint32 AccountMgr::GetId(std::string username)
uint32 AccountMgr::GetSecurity(uint32 acc_id)
{
- QueryResult *result = loginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id);
+ QueryResult *result = LoginDatabase.PQuery("SELECT gmlevel FROM account WHERE id = '%u'", acc_id);
if(result)
{
uint32 sec = (*result)[0].GetUInt32();
@@ -183,7 +183,7 @@ uint32 AccountMgr::GetSecurity(uint32 acc_id)
bool AccountMgr::GetName(uint32 acc_id, std::string &name)
{
- QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id);
+ QueryResult *result = LoginDatabase.PQuery("SELECT username FROM account WHERE id = '%u'", acc_id);
if(result)
{
name = (*result)[0].GetCppString();
@@ -197,9 +197,9 @@ bool AccountMgr::GetName(uint32 acc_id, std::string &name)
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
{
normilizeString(passwd);
- loginDatabase.escape_string(passwd);
+ LoginDatabase.escape_string(passwd);
- QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
+ QueryResult *result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%d' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))", accid, passwd.c_str());
if (result)
{
delete result;
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 5d091d55b1c..b51f24800ad 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -123,7 +123,7 @@ class CharacterHandler
void WorldSession::HandleCharEnum(QueryResult * result)
{
// keys can be non cleared if player open realm list and close it by 'cancel'
- loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
+ LoginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
@@ -281,7 +281,7 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
return;
}
- QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
+ QueryResult *resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
if ( resultacct )
{
Field *fields=resultacct->Fetch();
@@ -464,8 +464,8 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
pNewChar->SaveToDB();
charcount+=1;
- loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
- loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
+ LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
+ LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
delete pNewChar; // created only to call SaveToDB()
@@ -742,7 +742,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
pCurrChar->SendInitialPacketsAfterAddToMap();
CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow());
- loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
+ LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
pCurrChar->SetInGameTime( getMSTime() );
// announce group about member online (must be after add to player list to receive announce to self)
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 1d45afef5ea..d5a59360035 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -304,7 +304,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "locales_page_text", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesPageTextCommand, "", NULL },
{ "locales_quest", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesQuestCommand, "", NULL },
{ "waypoint_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadWpScriptsCommand, "", NULL },
- { "tickets", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMTicketReloadCommand, "", NULL },
+ { "gm_tickets", SEC_ADMINISTRATOR, true, &ChatHandler::HandleGMTicketReloadCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp
index 75f7a257caf..63a015f9802 100644
--- a/src/game/Level0.cpp
+++ b/src/game/Level0.cpp
@@ -197,7 +197,7 @@ bool ChatHandler::HandlePasswordCommand(const char* args)
std::string password_new = new_pass;
std::string password_new_c = new_pass_c;
- if (password_new != password_new_c)
+ if (strcmp(new_pass, new_pass_c) != 0)
{
SendSysMessage (LANG_NEW_PASSWORDS_NOT_MATCH);
SetSentErrorMessage (true);
@@ -243,14 +243,14 @@ bool ChatHandler::HandleLockAccountCommand(const char* args)
std::string argstr = (char*)args;
if (argstr == "on")
{
- loginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId());
+ LoginDatabase.PExecute( "UPDATE account SET locked = '1' WHERE id = '%d'",m_session->GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
return true;
}
if (argstr == "off")
{
- loginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId());
+ LoginDatabase.PExecute( "UPDATE account SET locked = '0' WHERE id = '%d'",m_session->GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED);
return true;
}
diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp
index 4489cbf1579..ba68df16f7f 100644
--- a/src/game/Level1.cpp
+++ b/src/game/Level1.cpp
@@ -275,19 +275,20 @@ bool ChatHandler::HandleGMTicketListCommand(const char* args)
SendSysMessage(LANG_COMMAND_TICKETSHOWLIST);
for(GmTicketList::iterator itr = ticketmgr.GM_TicketList.begin(); itr != ticketmgr.GM_TicketList.end(); ++itr)
{
- if((*itr)->closed == 1)
+ if((*itr)->closed != 0)
continue;
std::stringstream message;
message << "|cff00ff00Ticket|r: |cff00ccff" << (*itr)->guid;
message << ".|r |cff00ff00created by:|r |cff00ccff" << (*itr)->name;
message << ".|r |cff00ff00Last change:|r |cff00ccff " << secsToTimeString(time(NULL) - (*itr)->timestamp, true, false) << " ago.";
- if((*itr)->assignedToGM != 0 && objmgr.GetPlayer((*itr)->assignedToGM))
+ if((*itr)->assignedToGM != 0)
{
- std::string gmname = objmgr.GetPlayer((*itr)->assignedToGM)->GetName();
+ std::string gmname;
+ objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname);
message << "|r |cff00ff00Assigned to:|r |cff00ccff " << gmname;
}
- SendGlobalGMSysMessage(message.str().c_str());
+ SendSysMessage(message.str().c_str());
}
return true;
}
@@ -298,7 +299,7 @@ bool ChatHandler::HandleGMTicketListOnlineCommand(const char* args)
SendSysMessage(LANG_COMMAND_TICKETSHOWONLINELIST);
for(GmTicketList::iterator itr = ticketmgr.GM_TicketList.begin(); itr != ticketmgr.GM_TicketList.end(); ++itr)
{
- if((*itr)->closed == 1 || !objmgr.GetPlayer((*itr)->playerGuid))
+ if((*itr)->closed != 0 || !objmgr.GetPlayer((*itr)->playerGuid))
continue;
std::stringstream message;
@@ -307,10 +308,11 @@ bool ChatHandler::HandleGMTicketListOnlineCommand(const char* args)
message << ".|r |cff00ff00Last change:|r |cff00ccff " << secsToTimeString((time(NULL) - (*itr)->timestamp), true, false) << " ago.";
if((*itr)->assignedToGM != 0 && objmgr.GetPlayer((*itr)->assignedToGM))
{
- std::string gmname = objmgr.GetPlayer((*itr)->assignedToGM)->GetName();
+ std::string gmname;
+ objmgr.GetPlayerNameByGUID((*itr)->assignedToGM, gmname);
message << "|r |cff00ff00Assigned to:|r |cff00ccff " << gmname;
}
- SendGlobalGMSysMessage(message.str().c_str());
+ SendSysMessage(message.str().c_str());
}
return true;
}
@@ -334,7 +336,8 @@ bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args)
message << ".|r |cff00ff00Last change:|r |cff00ccff " << secsToTimeString((time(NULL)-ticket->timestamp), true, false) << " ago.";
if(ticket->assignedToGM != 0 && objmgr.GetPlayer(ticket->assignedToGM))
{
- std::string gmname = objmgr.GetPlayer(ticket->assignedToGM)->GetName();
+ std::string gmname;
+ objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname);
message << "|r |cff00ff00Assigned to:|r |cff00ccff " << gmname;
}
message << "|r\n|cff00ff00Message:|r " << ticket->message;
@@ -342,7 +345,7 @@ bool ChatHandler::HandleGMTicketGetByIdCommand(const char* args)
{
message << "|r |cff00ff00Comment:|r |cff00ccff " << ticket->comment;
}
- PSendSysMessage(message.str().c_str());
+ SendSysMessage(message.str().c_str());
return true;
}
@@ -364,7 +367,8 @@ bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args)
message << ".|r |cff00ff00Last change:|r |cff00ccff " << secsToTimeString((time(NULL)-ticket->timestamp), true, false) << " ago.";
if(ticket->assignedToGM != 0 && objmgr.GetPlayer(ticket->assignedToGM))
{
- std::string gmname = objmgr.GetPlayer(ticket->assignedToGM)->GetName();
+ std::string gmname;
+ objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname);
message << "|r |cff00ff00Assigned to:|r |cff00ccff " << gmname;
}
message << "|r\n|cff00ff00Message:|r " << ticket->message;
@@ -372,7 +376,7 @@ bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args)
{
message << "|r |cff00ff00Comment:|r |cff00ccff " << ticket->comment;
}
- PSendSysMessage(message.str().c_str());
+ SendSysMessage(message.str().c_str());
return true;
}
@@ -383,22 +387,22 @@ bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args)
uint64 tguid = atoi(args);
GM_Ticket *ticket = ticketmgr.GetGMTicket(tguid);
- if(!ticket || ticket->closed == 1)
+ if(!ticket || ticket->closed != 0)
{
SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
- return false;
+ return true;
}
if(ticket && ticket->assignedToGM != 0 && ticket->assignedToGM != m_session->GetPlayer()->GetGUID())
{
PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->guid);
- return false;
+ return true;
}
- sWorld.SendGMText(LANG_COMMAND_TICKETCLOSED, ticket->name.c_str(), ticket->guid);
- ticketmgr.RemoveGMTicket(ticket->guid);
+ sWorld.SendGMText(LANG_COMMAND_TICKETCLOSED, m_session->GetPlayer()->GetName(), ticket->guid);
+ ticketmgr.RemoveGMTicket(ticket->guid, m_session->GetPlayer()->GetGUID());
Player *plr = objmgr.GetPlayer(ticket->playerGuid);
if(!plr || !plr->IsInWorld())
- return false;
+ return true;
// send abandon ticket
WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4);
@@ -428,40 +432,38 @@ bool ChatHandler::HandleGMTicketAssignToCommand(const char* args)
std::string gmname;
GM_Ticket *ticket = ticketmgr.GetGMTicket(ticketGuid);
- if(!ticket || ticket->closed == 1)
+ if(!ticket || ticket->closed != 0)
{
SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
}
- Player *plr = objmgr.GetPlayer(targm.c_str());
- if(!plr || !plr->IsInWorld() || plr->GetSession()->GetSecurity() < SEC_MODERATOR)
+ uint64 tarGUID = objmgr.GetPlayerGUIDByName(targm.c_str());
+ uint64 accid = objmgr.GetPlayerAccountIdByGUID(tarGUID);
+ QueryResult *result = LoginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `id` = '%u'", accid);
+ if(!tarGUID|| !result || result->Fetch()->GetUInt32() < SEC_MODERATOR)
{
SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A);
return true;
}
- if(ticket->assignedToGM == plr->GetGUID())
+ if(ticket->assignedToGM == tarGUID)
{
PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->guid);
return true;
}
+ objmgr.GetPlayerNameByGUID(tarGUID, gmname);
if(ticket->assignedToGM != 0 && ticket->assignedToGM != cplr->GetGUID())
{
- Player *aplr = objmgr.GetPlayer(ticket->assignedToGM);
- if(aplr && aplr->IsInWorld())
- {
- gmname = aplr->GetName();
- PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str());
- return true;
- }
+ PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->guid, gmname.c_str());
+ return true;
}
- ticket->assignedToGM = plr->GetGUID();
+ ticket->assignedToGM = tarGUID;
ticketmgr.UpdateGMTicket(ticket);
std::stringstream ss;
ss << "|cff00ff00Ticket:|r ";
ss << "|cffff00ff" << ticket->guid << ". " << cplr->GetName() << "|r";
ss << "|cff00ff00 assigned to:|r ";
- ss << "|cffff00ff\"" << targetgm << "\".";
+ ss << "|cffff00ff\"" << gmname << "\".";
SendGlobalGMSysMessage(ss.str().c_str());
return true;
}
@@ -475,19 +477,20 @@ bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args)
Player *cplr = m_session->GetPlayer();
GM_Ticket *ticket = ticketmgr.GetGMTicket(ticketGuid);
- if(!ticket|| ticket->closed)
+ if(!ticket|| ticket->closed != 0)
{
SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
}
- if(ticket->assignedToGM = 0)
+ if(ticket->assignedToGM == 0)
{
SendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED);
return true;
}
- Player *plr = objmgr.GetPlayer(ticket->assignedToGM);
-
+ std::string gmname;
+ objmgr.GetPlayerNameByGUID(ticket->assignedToGM, gmname);
+ Player *plr = objmgr.GetPlayer(ticket->assignedToGM);
if(plr && plr->IsInWorld() && plr->GetSession()->GetSecurity() > cplr->GetSession()->GetSecurity())
{
SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY);
@@ -519,7 +522,7 @@ bool ChatHandler::HandleGMTicketCommentCommand(const char* args)
Player *cplr = m_session->GetPlayer();
GM_Ticket *ticket = ticketmgr.GetGMTicket(ticketGuid);
- if(!ticket || ticket->closed == 1)
+ if(!ticket || ticket->closed != 0)
{
PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
@@ -553,14 +556,17 @@ bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args)
SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
}
- if(!ticket->closed == 1)
+ if(ticket->closed == 0)
{
SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST);
return true;
}
- std::string gmname = m_session->GetPlayer()->GetName();
- sWorld.SendGMText(LANG_COMMAND_TICKETDELETED, ticket->guid, gmname.c_str());
+ std::stringstream ss;
+ ss << "|cff00ff00Ticket:|r ";
+ ss << "|cffff00ff" << m_session->GetPlayer()->GetName() << "|r";
+ ss << "|cff00ff00 deleted.|r";
+ SendGlobalGMSysMessage(ss.str().c_str());
Player *plr = objmgr.GetPlayer(ticket->playerGuid);
ticketmgr.DeleteGMTicketPermanently(ticket->guid);
if(plr && plr->IsInWorld())
diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp
index afe22846cdd..c5db2cc2869 100644
--- a/src/game/Level2.cpp
+++ b/src/game/Level2.cpp
@@ -115,7 +115,7 @@ bool ChatHandler::HandleMuteCommand(const char* args)
if (chr)
chr->GetSession()->m_muteTime = mutetime;
- loginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
+ LoginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
if(chr)
ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
@@ -188,7 +188,7 @@ bool ChatHandler::HandleUnmuteCommand(const char* args)
chr->GetSession()->m_muteTime = 0;
}
- loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
+ LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
if(chr)
ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
@@ -1896,7 +1896,7 @@ bool ChatHandler::HandlePInfoCommand(const char* args)
uint32 security = 0;
std::string last_login = GetTrinityString(LANG_ERROR);
- QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId);
+ QueryResult* result = LoginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId);
if(result)
{
Field* fields = result->Fetch();
@@ -3870,9 +3870,9 @@ bool ChatHandler::HandleLookupPlayerIpCommand(const char* args)
char* limit_str = strtok (NULL, " ");
int32 limit = limit_str ? atoi (limit_str) : -1;
- loginDatabase.escape_string (ip);
+ LoginDatabase.escape_string (ip);
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
+ QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
@@ -3889,9 +3889,9 @@ bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args)
if (!AccountMgr::normilizeString (account))
return false;
- loginDatabase.escape_string (account);
+ LoginDatabase.escape_string (account);
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
+ QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
@@ -3906,9 +3906,9 @@ bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args)
char* limit_str = strtok (NULL, " ");
int32 limit = limit_str ? atoi (limit_str) : -1;
- loginDatabase.escape_string (email);
+ LoginDatabase.escape_string (email);
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
+ QueryResult* result = LoginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
return LookupPlayerSearchCommand (result,limit);
}
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index a17d9d621b1..9c8c234c91c 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -764,7 +764,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
PSendSysMessage(LANG_YOURS_SECURITY_CHANGED, m_session->GetPlayer()->GetName(), gm);
}
- loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
+ LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
return true;
}else
{
@@ -805,7 +805,7 @@ bool ChatHandler::HandleAccountSetGmLevelCommand(const char* args)
}
PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm);
- loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
+ LoginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE id = '%u'", gm, targetAccountId);
return true;
}
}
@@ -5213,7 +5213,7 @@ bool ChatHandler::HandleBanInfoCharacterCommand(const char* args)
bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname)
{
- QueryResult *result = loginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid);
+ QueryResult *result = LoginDatabase.PQuery("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby FROM account_banned WHERE id = '%u' ORDER BY bandate ASC",accountid);
if(!result)
{
PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname);
@@ -5253,8 +5253,8 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args)
std::string IP = cIP;
- loginDatabase.escape_string(IP);
- QueryResult *result = loginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str());
+ LoginDatabase.escape_string(IP);
+ QueryResult *result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'",IP.c_str());
if(!result)
{
PSendSysMessage(LANG_BANINFO_NOIP);
@@ -5272,14 +5272,14 @@ bool ChatHandler::HandleBanInfoIPCommand(const char* args)
bool ChatHandler::HandleBanListCharacterCommand(const char* args)
{
- loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok ((char*)args, " ");
if(!cFilter)
return false;
std::string filter = cFilter;
- loginDatabase.escape_string(filter);
+ LoginDatabase.escape_string(filter);
QueryResult* result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),filter.c_str());
if (!result)
{
@@ -5292,22 +5292,22 @@ bool ChatHandler::HandleBanListCharacterCommand(const char* args)
bool ChatHandler::HandleBanListAccountCommand(const char* args)
{
- loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok((char*)args, " ");
std::string filter = cFilter ? cFilter : "";
- loginDatabase.escape_string(filter);
+ LoginDatabase.escape_string(filter);
QueryResult* result;
if(filter.empty())
{
- result = loginDatabase.Query("SELECT account.id, username FROM account, account_banned"
+ result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id");
}
else
{
- result = loginDatabase.PQuery("SELECT account.id, username FROM account, account_banned"
+ result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 AND username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" GROUP BY account.id",
filter.c_str());
}
@@ -5333,7 +5333,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
Field* fields = result->Fetch();
uint32 accountid = fields[0].GetUInt32();
- QueryResult* banresult = loginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid);
+ QueryResult* banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id",accountid);
if(banresult)
{
Field* fields2 = banresult->Fetch();
@@ -5364,7 +5364,7 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
accmgr.GetName (account_id,account_name);
// No SQL injection. id is uint32.
- QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
+ QueryResult *banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
if (banInfo)
{
Field *fields2 = banInfo->Fetch();
@@ -5401,23 +5401,23 @@ bool ChatHandler::HandleBanListHelper(QueryResult* result)
bool ChatHandler::HandleBanListIPCommand(const char* args)
{
- loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = strtok((char*)args, " ");
std::string filter = cFilter ? cFilter : "";
- loginDatabase.escape_string(filter);
+ LoginDatabase.escape_string(filter);
QueryResult* result;
if(filter.empty())
{
- result = loginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
+ result = LoginDatabase.Query ("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())"
" ORDER BY unbandate" );
}
else
{
- result = loginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
+ result = LoginDatabase.PQuery( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")
" ORDER BY unbandate",filter.c_str() );
}
@@ -6205,7 +6205,7 @@ bool ChatHandler::HandleInstanceSaveDataCommand(const char * /*args*/)
bool ChatHandler::HandleGMListFullCommand(const char* /*args*/)
{
///- Get the accounts with GM Level >0
- QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
+ QueryResult *result = LoginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
if(result)
{
SendSysMessage(LANG_GMLIST);
@@ -6284,7 +6284,7 @@ bool ChatHandler::HandleAccountSetAddonCommand(const char* args)
return false;
// No SQL injection
- loginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id);
+ LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'",lev,account_id);
PSendSysMessage(LANG_ACCOUNT_SETADDON,account_name.c_str(),account_id,lev);
return true;
}
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 2107d792c7d..2d8a898132e 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1367,7 +1367,7 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
uint32 accid = plr->GetSession()->GetAccountId();
- QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
+ QueryResult *result = LoginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
if(!result)
{
SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index 6a87d52cfca..82259cbba4d 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -73,6 +73,9 @@ void PetAI::AttackStart(Unit *u)
if(i_pet.Attack(u,true))
{
+ i_pet.SetInCombatWith(u);
+ u->SetInCombatWith(&i_pet);
+
i_pet.clearUnitState(UNIT_STAT_FOLLOW);
// TMGs call CreatureRelocation which via MoveInLineOfSight can call this function
// thus with the following clear the original TMG gets invalidated and crash, doh
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 1fca0b32067..cbf5c8dbfc5 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -3748,7 +3748,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = '%u'",guid);
CharacterDatabase.CommitTransaction();
- //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
+ //LoginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId);
}
@@ -3815,7 +3815,7 @@ void Player::BuildPlayerRepop()
// BG - remove insignia related
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
- SendCorpseReclaimDelay();
+// SendCorpseReclaimDelay();
// to prevent cheating
corpse->ResetGhostTime();
@@ -3923,6 +3923,7 @@ void Player::KillPlayer()
m_deathTimer = 6*MINUTE*1000;
UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill
+ SendCorpseReclaimDelay();
// don't create corpse at this moment, player might be falling
@@ -19283,7 +19284,8 @@ uint32 Player::GetCorpseReclaimDelay(bool pvp) const
time_t now = time(NULL);
// 0..2 full period
- uint32 count = (now < m_deathExpireTime) ? (m_deathExpireTime - now)/DEATH_EXPIRE_STEP : 0;
+ // should be ceil(x)-1 but not floor(x)
+ uint32 count = (now < m_deathExpireTime - 1) ? (m_deathExpireTime - 1 - now)/DEATH_EXPIRE_STEP : 0;
return copseReclaimDelay[count];
}
@@ -19312,17 +19314,21 @@ void Player::UpdateCorpseReclaimDelay()
void Player::SendCorpseReclaimDelay(bool load)
{
Corpse* corpse = GetCorpse();
- if(!corpse)
+ if(load && !corpse)
return;
+ bool pvp;
+ if(corpse)
+ pvp = (corpse->GetType() == CORPSE_RESURRECTABLE_PVP);
+ else
+ pvp = (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH);
+
uint32 delay;
if(load)
{
if(corpse->GetGhostTime() > m_deathExpireTime)
return;
- bool pvp = corpse->GetType()==CORPSE_RESURRECTABLE_PVP;
-
uint32 count;
if( pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP) ||
!pvp && sWorld.getConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE) )
@@ -19343,7 +19349,7 @@ void Player::SendCorpseReclaimDelay(bool load)
delay = expected_time-now;
}
else
- delay = GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP);
+ delay = GetCorpseReclaimDelay(pvp);
//! corpse reclaim delay 30 * 1000ms or longer at often deaths
WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4);
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index d48294a77a1..20e10384a49 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -938,7 +938,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
// Add bonuses and fill damageInfo struct
- caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo);
+ caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo);
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
@@ -5536,19 +5536,14 @@ void Spell::CalculateDamageDoneForAllTargets()
int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *multiplier)
{
- m_damage = 0;
+ int32 damageDone = 0;
unitTarget = unit;
for(uint32 i = 0; i < 3; ++i)
{
if (effectMask & (1<<i))
{
- if(m_applyMultiplierMask & (1 << i))
- {
- damage = CalculateDamage(i, NULL) * m_damageMultipliers[i];
- m_damageMultipliers[i] *= multiplier[i];
- }
- else
- damage = CalculateDamage(i, NULL);
+ m_damage = 0;
+ damage = CalculateDamage(i, NULL);
switch(m_spellInfo->Effect[i])
{
@@ -5565,7 +5560,18 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul
SpellDamageHeal(i);
break;
}
+
+ if(m_damage > 0 && m_originalCaster)
+ m_damage = m_originalCaster->SpellDamageBonus(unit, m_spellInfo, m_damage, SPELL_DIRECT_DAMAGE);
+ if(m_applyMultiplierMask & (1 << i))
+ {
+ m_damage *= m_damageMultipliers[i];
+ m_damageMultipliers[i] *= multiplier[i];
+ }
+
+ damageDone += m_damage;
}
}
- return m_damage;
+
+ return damageDone;
}
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 66a91fbc19b..8ae85c89ff0 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -6033,7 +6033,8 @@ void Aura::PeriodicTick()
SpellEntry const* spellProto = GetSpellProto();
//maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
- pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
+ //no SpellDamageBonus for burn mana
+ pCaster->CalculateSpellDamageTaken(&damageInfo, gain, spellProto);
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
// Set trigger flag
diff --git a/src/game/TicketHandler.cpp b/src/game/TicketHandler.cpp
index f3374332f79..1e1d97fd4ce 100644
--- a/src/game/TicketHandler.cpp
+++ b/src/game/TicketHandler.cpp
@@ -36,8 +36,6 @@ void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
// always do a packet check
CHECK_PACKET_SIZE(recv_data, 4*4+1+2*4);
- uint32 map;
- float x, y, z;
std::string ticketText = "";
std::string ticketText2 = "";
GM_Ticket *ticket = new GM_Ticket;
@@ -45,13 +43,9 @@ void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
WorldPacket data(SMSG_GMTICKET_CREATE, 4);
// recv Data
- recv_data >> map;
- recv_data >> x;
- recv_data >> y;
- recv_data >> z;
recv_data >> ticketText;
- // get additional data
+ // get additional data, rarely used
recv_data >> ticketText2;
// assign values
@@ -65,7 +59,7 @@ void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
ticket->comment = "";
// remove ticket by player, shouldn't happen
- ticketmgr.RemoveGMTicketByPlayer(GetPlayer()->GetGUID());
+ ticketmgr.RemoveGMTicketByPlayer(GetPlayer()->GetGUID(), GetPlayer()->GetGUID());
// add ticket
ticketmgr.AddGMTicket(ticket, false);
@@ -140,7 +134,7 @@ void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/)
SendPacket(&data);
sWorld.SendGMText(LANG_COMMAND_TICKETPLAYERABANDON, GetPlayer()->GetName(), ticket->guid );
- ticketmgr.RemoveGMTicketByPlayer(GetPlayer()->GetGUID());
+ ticketmgr.RemoveGMTicketByPlayer(GetPlayer()->GetGUID(), GetPlayer()->GetGUID());
}
}
diff --git a/src/game/TicketMgr.cpp b/src/game/TicketMgr.cpp
index 0f1f7501e67..ffa8c522672 100644
--- a/src/game/TicketMgr.cpp
+++ b/src/game/TicketMgr.cpp
@@ -24,13 +24,9 @@
#include "ObjectMgr.h"
#include "Language.h"
#include "Player.h"
-INSTANTIATE_SINGLETON_1( TicketMgr );
-
#include "Common.h"
-//#include "Log.h"
#include "ObjectAccessor.h"
-
-
+INSTANTIATE_SINGLETON_1( TicketMgr );
GM_Ticket* TicketMgr::GetGMTicket(uint64 ticketGuid)
{
@@ -106,7 +102,7 @@ void TicketMgr::DeleteGMTicketPermanently(uint64 ticketGuid)
}
// delete database record
- CharacterDatabase.PExecute("DELETE FROM gm_tickets WHERE guid=%u", ticketGuid);
+ CharacterDatabase.PExecute("DELETE FROM `gm_tickets` WHERE guid= '%u'", ticketGuid);
}
@@ -114,13 +110,13 @@ void TicketMgr::LoadGMTickets()
{
// Delete all out of object holder
GM_TicketList.clear();
- QueryResult *result = CharacterDatabase.Query( "SELECT `guid`, `playerGuid`, `name`, `message`, `timestamp`, `closed`, `assignedto`, `comment` FROM gm_tickets WHERE closed = '0'" );
+ QueryResult *result = CharacterDatabase.Query( "SELECT `guid`, `playerGuid`, `name`, `message`, `timestamp`, `closed`, `assignedto`, `comment` FROM `gm_tickets` WHERE `closed` = '0'" );
GM_Ticket *ticket;
- //ticket = NULL;
if(!result)
return;
+ // Assign values from SQL to the object holder
do
{
Field *fields = result->Fetch();
@@ -143,13 +139,13 @@ void TicketMgr::LoadGMTickets()
delete result;
}
-void TicketMgr::RemoveGMTicket(uint64 ticketGuid)
+void TicketMgr::RemoveGMTicket(uint64 ticketGuid, uint64 GMguid)
{
for(GmTicketList::iterator i = GM_TicketList.begin(); i != GM_TicketList.end();)
{
if((*i)->guid == ticketGuid && (*i)->closed == 0)
{
- (*i)->closed = 1;
+ (*i)->closed = GMguid;
SaveGMTicket((*i));
}
++i;
@@ -157,13 +153,13 @@ void TicketMgr::RemoveGMTicket(uint64 ticketGuid)
}
-void TicketMgr::RemoveGMTicketByPlayer(uint64 playerGuid)
+void TicketMgr::RemoveGMTicketByPlayer(uint64 playerGuid, uint64 GMguid)
{
for(GmTicketList::iterator i = GM_TicketList.begin(); i != GM_TicketList.end();)
{
if((*i)->playerGuid == playerGuid && (*i)->closed == 0)
{
- (*i)->closed = true;
+ (*i)->closed = GMguid;
SaveGMTicket((*i));
}
++i;
@@ -173,15 +169,15 @@ void TicketMgr::RemoveGMTicketByPlayer(uint64 playerGuid)
void TicketMgr::SaveGMTicket(GM_Ticket* ticket)
{
std::stringstream ss;
- ss << "REPLACE INTO gm_tickets (`guid`, `playerGuid`, `name`, `message`, `timestamp`, `closed`, `assignedto`, `comment`) VALUES(";
- ss << ticket->guid << ", ";
- ss << ticket->playerGuid << ", '";
- ss << ticket->name << "', '";
- ss << ticket->message << "', " ;
- ss << ticket->timestamp << ", ";
- ss << ticket->closed << ", '";
- ss << ticket->assignedToGM << "', '";
- ss << ticket->comment << "');";
+ ss << "REPLACE INTO `gm_tickets` (`guid`, `playerGuid`, `name`, `message`, `timestamp`, `closed`, `assignedto`, `comment`) VALUES(\"";
+ ss << ticket->guid << "\", \"";
+ ss << ticket->playerGuid << "\", \"";
+ ss << ticket->name << "\", \"";
+ ss << ticket->message << "\", \"" ;
+ ss << ticket->timestamp << "\", \"";
+ ss << ticket->closed << "\", \"";
+ ss << ticket->assignedToGM << "\", \"";
+ ss << ticket->comment << "\");";
CharacterDatabase.BeginTransaction();
CharacterDatabase.Execute(ss.str().c_str());
@@ -203,5 +199,5 @@ uint64 TicketMgr::GenerateTicketID()
delete result;
}
- return m_ticketid;
+ return ++m_ticketid;
} \ No newline at end of file
diff --git a/src/game/TicketMgr.h b/src/game/TicketMgr.h
index e41be9db5c3..33a9598e7cf 100644
--- a/src/game/TicketMgr.h
+++ b/src/game/TicketMgr.h
@@ -39,27 +39,13 @@ struct GM_Ticket
std::string comment;
};
-enum GMticketType
-{
- GM_TICKET_TYPE_STUCK = 1,
- GM_TICKET_TYPE_BEHAVIOR_HARASSMENT = 2,
- GM_TICKET_TYPE_GUILD = 3,
- GM_TICKET_TYPE_ITEM = 4,
- GM_TICKET_TYPE_ENVIRONMENTAL = 5,
- GM_TICKET_TYPE_NON_QUEST_CREEP = 6,
- GM_TICKET_TYPE_QUEST_QUEST_NPC = 7,
- GM_TICKET_TYPE_TECHNICAL = 8,
- GM_TICKET_TYPE_ACCOUNT_BILLING = 9,
- GM_TICKET_TYPE_CHARACTER = 10
-};
-
// Map Typedef
typedef std::list<GM_Ticket*> GmTicketList;
class TicketMgr
{
public:
- TicketMgr(){} //constructor
+ TicketMgr(){m_ticketid = 1;} //constructor
~TicketMgr(){} //destructor
// Object Holder
@@ -69,8 +55,8 @@ class TicketMgr
void DeleteAllRemovedGMTickets();
void DeleteGMTicketPermanently(uint64 ticketGuid);
void LoadGMTickets();
- void RemoveGMTicketByPlayer(uint64 playerGuid);
- void RemoveGMTicket(uint64 ticketGuid);
+ void RemoveGMTicketByPlayer(uint64 playerGuid, uint64 GMguid);
+ void RemoveGMTicket(uint64 ticketGuid, uint64 GMguid);
void UpdateGMTicket(GM_Ticket *ticket);
void SaveGMTicket(GM_Ticket* ticket);
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 766115742da..65689a71e84 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -1150,13 +1150,14 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
- CalculateSpellDamage(&damageInfo, damage, spellInfo);
+ damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
return damageInfo.damage;
}
-void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
+void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
{
SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
Unit *pVictim = damageInfo->target;
@@ -1184,16 +1185,16 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
{
//Calculate armor mitigation
- damage = CalcArmorReducedDamage(pVictim, damage);
+ //damage = CalcArmorReducedDamage(pVictim, damage);
// Get blocked status
blocked = isSpellBlocked(pVictim, spellInfo, attackType);
}
// Magical Damage
- else
+ /*else
{
// Calculate damage bonus
damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
- }
+ }*/
if (crit)
{
damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
@@ -1239,7 +1240,7 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
case SPELL_DAMAGE_CLASS_MAGIC:
{
// Calculate damage bonus
- damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ //damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
// If crit add critical bonus
if (crit)
{
@@ -1253,6 +1254,9 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
break;
}
+ if( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
+ damage = CalcArmorReducedDamage(pVictim, damage);
+
// Calculate absorb resist
if(damage > 0)
{
@@ -6713,7 +6717,6 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
((WorldObject*)this)->SendMessageToSet(&data, true);
((Creature*)this)->CallAssistance();
- ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
}
// delay offhand weapon attack to next attack time
@@ -7038,6 +7041,10 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
if(!spellProto || !pVictim || damagetype==DIRECT_DAMAGE )
return pdamage;
+ if(spellProto->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)
+ return pdamage;
+ //damage = CalcArmorReducedDamage(pVictim, damage);
+
int32 BonusDamage = 0;
if( GetTypeId()==TYPEID_UNIT )
{
@@ -8299,18 +8306,19 @@ void Unit::SetInCombatState(bool PvP)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
- SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
+ if(GetTypeId() != TYPEID_PLAYER)
+ ((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
- if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
{
- if(Pet *pet = GetPet())
- {
- pet->UpdateSpeed(MOVE_RUN, true);
- pet->UpdateSpeed(MOVE_SWIM, true);
- pet->UpdateSpeed(MOVE_FLIGHT, true);
- }
+ UpdateSpeed(MOVE_RUN, true);
+ UpdateSpeed(MOVE_SWIM, true);
+ UpdateSpeed(MOVE_FLIGHT, true);
}
+ else if(!isCharmed())
+ return;
+
+ SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
}
void Unit::ClearInCombat()
@@ -8318,19 +8326,22 @@ void Unit::ClearInCombat()
m_CombatTimer = 0;
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
- RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
-
// Player's state will be cleared in Player::UpdateContestedPvP
if(GetTypeId()!=TYPEID_PLAYER)
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
- if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
{
- if(Pet *pet = GetPet())
+ if(Unit *owner = GetOwner())
+ {
for(int i = 0; i < MAX_MOVE_TYPE; ++i)
- pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
+ SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true);
+ }
}
+ else if(!isCharmed())
+ return;
+
+ RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
}
//TODO: remove this function
@@ -10086,7 +10097,8 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
{
sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
- CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);
+ uint32 damage = SpellDamageBonus(pTarget, spellInfo, auraModifier->m_amount, SPELL_DIRECT_DAMAGE);
+ CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
SendSpellNonMeleeDamageLog(&damageInfo);
DealSpellDamage(&damageInfo, true);
break;
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 98a49e519ac..238490d9428 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -951,7 +951,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss);
- void CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType = BASE_ATTACK);
+ void CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss);
float MeleeSpellMissChance(const Unit *pVictim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const;
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 9bb936be6af..83543aa4f74 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -267,7 +267,7 @@ World::AddSession_ (WorldSession* s)
float popu = GetActiveSessionCount (); //updated number of users on the server
popu /= pLimit;
popu *= 2;
- loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
+ LoginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
sLog.outDetail ("Server Population (%f).", popu);
}
}
@@ -1085,7 +1085,7 @@ void World::SetInitialWorldSettings()
// not send custom type REALM_FFA_PVP to realm list
uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_GAME_TYPE);
uint32 realm_zone = getConfig(CONFIG_REALM_ZONE);
- loginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
+ LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
///- Remove the bones after a restart
CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0'");
@@ -1404,7 +1404,7 @@ void World::SetInitialWorldSettings()
objmgr.LoadTransportEvents();
sLog.outString("Deleting expired bans..." );
- loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
sLog.outString("Calculate next daily quest reset time..." );
InitDailyQuestResetTime();
@@ -2649,10 +2649,10 @@ bool World::KickPlayer(const std::string& playerName)
/// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author)
{
- loginDatabase.escape_string(nameOrIP);
- loginDatabase.escape_string(reason);
+ LoginDatabase.escape_string(nameOrIP);
+ LoginDatabase.escape_string(reason);
std::string safe_author=author;
- loginDatabase.escape_string(safe_author);
+ LoginDatabase.escape_string(safe_author);
uint32 duration_secs = TimeStringToSecs(duration);
QueryResult *resultAccounts = NULL; //used for kicking
@@ -2662,12 +2662,12 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura
{
case BAN_IP:
//No SQL injection as strings are escaped
- resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
- 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());
+ resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
+ 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());
break;
case BAN_ACCOUNT:
//No SQL injection as string is escaped
- resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
+ resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
break;
case BAN_CHARACTER:
//No SQL injection as string is escaped
@@ -2694,7 +2694,7 @@ BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, std::string dura
if(mode!=BAN_IP)
{
//No SQL injection as strings are escaped
- loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
+ LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
account,duration_secs,safe_author.c_str(),reason.c_str());
}
@@ -2713,8 +2713,8 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
{
if (mode == BAN_IP)
{
- loginDatabase.escape_string(nameOrIP);
- loginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
+ LoginDatabase.escape_string(nameOrIP);
+ LoginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
}
else
{
@@ -2728,7 +2728,7 @@ bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
return false;
//NO SQL injection as account is uint32
- loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
+ LoginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
}
return true;
}
@@ -2925,8 +2925,8 @@ void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId
Field *fields = resultCharCount->Fetch();
uint32 charCount = fields[0].GetUInt32();
delete resultCharCount;
- loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
- loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
+ LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
+ LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
}
}
@@ -2989,7 +2989,7 @@ void World::SetPlayerLimit( int32 limit, bool needUpdate )
m_playerLimit = limit;
if(db_update_need)
- loginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
+ LoginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
}
void World::UpdateMaxSessionCounters()
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 581b44b9e95..231d7783d9e 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -328,7 +328,7 @@ void WorldSession::LogoutPlayer(bool Save)
///- Reset the online field in the account table
// no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage
//No SQL injection as AccountID is uint32
- loginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId());
+ LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = '%u'", GetAccountId());
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
Guild *guild = objmgr.GetGuildById(_player->GetGuildId());
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp
index 2ae97819116..1f77e1111e5 100644
--- a/src/game/WorldSocket.cpp
+++ b/src/game/WorldSocket.cpp
@@ -720,11 +720,11 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Get the account information from the realmd database
std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below
- loginDatabase.escape_string (safe_account);
+ LoginDatabase.escape_string (safe_account);
// No SQL injection, username escaped.
QueryResult *result =
- loginDatabase.PQuery ("SELECT "
+ LoginDatabase.PQuery ("SELECT "
"id, " //0
"gmlevel, " //1
"sessionkey, " //2
@@ -789,7 +789,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
vold,
vStr);
- loginDatabase.PExecute ("UPDATE account "
+ LoginDatabase.PExecute ("UPDATE account "
"SET "
"v = '0', "
"s = '0' "
@@ -841,7 +841,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Re-check account ban (same check as in realmd)
QueryResult *banresult =
- loginDatabase.PQuery ("SELECT "
+ LoginDatabase.PQuery ("SELECT "
"bandate, "
"unbandate "
"FROM account_banned "
@@ -907,9 +907,9 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket)
// Update the last_ip in the database
// No SQL injection, username escaped.
- loginDatabase.escape_string (address);
+ LoginDatabase.escape_string (address);
- loginDatabase.PExecute ("UPDATE account "
+ LoginDatabase.PExecute ("UPDATE account "
"SET last_ip = '%s' "
"WHERE username = '%s'",
address.c_str (),
diff --git a/src/shared/Database/DatabaseEnv.h b/src/shared/Database/DatabaseEnv.h
index cc09b7611db..d984a838c90 100644
--- a/src/shared/Database/DatabaseEnv.h
+++ b/src/shared/Database/DatabaseEnv.h
@@ -53,6 +53,6 @@ typedef DatabaseMysql DatabaseType;
extern DatabaseType WorldDatabase;
extern DatabaseType CharacterDatabase;
-extern DatabaseType loginDatabase;
+extern DatabaseType LoginDatabase;
#endif
diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp
index 78c6e0dbb85..267a8d41a27 100644
--- a/src/trinitycore/CliRunnable.cpp
+++ b/src/trinitycore/CliRunnable.cpp
@@ -194,7 +194,7 @@ bool ChatHandler::HandleAccountOnlineListCommand(const char* args)
///- Get the username, last IP and GM level of each account
// No SQL injection. account is uint32.
// 0 1 2 3
- QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account);
+ QueryResult *resultLogin = LoginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account);
if(resultLogin)
{
diff --git a/src/trinitycore/Main.cpp b/src/trinitycore/Main.cpp
new file mode 100644
index 00000000000..a4bcf717d62
--- /dev/null
+++ b/src/trinitycore/Main.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup Trinityd Trinity Daemon
+/// @{
+/// \file
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Config/ConfigEnv.h"
+#include "Log.h"
+#include "Master.h"
+
+#ifndef _TRINITY_CORE_CONFIG
+# define _TRINITY_CORE_CONFIG "trinitycore.conf"
+#endif //_TRINITY_CORE_CONFIG
+
+// Format is YYYYMMDDRR where RR is the change in the conf file
+// for that day.
+#ifndef _TRINITY_CORE_CONFVER
+# define _TRINITY_CORE_CONFVER 2008022901
+#endif //_TRINITY_CORE_CONFVER
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+char serviceName[] = "Trinityd";
+char serviceLongName[] = "Trinity core service";
+char serviceDescription[] = "Massive Network Game Object Server";
+/*
+ * -1 - not in service mode
+ * 0 - stopped
+ * 1 - running
+ * 2 - paused
+ */
+int m_ServiceStatus = -1;
+#endif
+
+DatabaseType WorldDatabase; ///< Accessor to the world database
+DatabaseType CharacterDatabase; ///< Accessor to the character database
+DatabaseType LoginDatabase; ///< Accessor to the realm/login database
+
+uint32 realmID; ///< Id of the realm
+
+/// Print out the usage string for this program on the console.
+void usage(const char *prog)
+{
+ sLog.outString("Usage: \n %s [<options>]\n"
+ " -c config_file use config_file as configuration file\n\r"
+ #ifdef WIN32
+ " Running as service functions:\n\r"
+ " --service run as service\n\r"
+ " -s install install service\n\r"
+ " -s uninstall uninstall service\n\r"
+ #endif
+ ,prog);
+}
+
+/// Launch the Trinity server
+extern int main(int argc, char **argv)
+{
+ ///- Command line parsing to get the configuration file name
+ char const* cfg_file = _TRINITY_CORE_CONFIG;
+ int c=1;
+ while( c < argc )
+ {
+ if( strcmp(argv[c],"-c") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -c option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ else
+ cfg_file = argv[c];
+ }
+
+ #ifdef WIN32
+ ////////////
+ //Services//
+ ////////////
+ if( strcmp(argv[c],"-s") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -s option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ if( strcmp(argv[c],"install") == 0)
+ {
+ if (WinServiceInstall())
+ sLog.outString("Installing service");
+ return 1;
+ }
+ else if( strcmp(argv[c],"uninstall") == 0)
+ {
+ if(WinServiceUninstall())
+ sLog.outString("Uninstalling service");
+ return 1;
+ }
+ else
+ {
+ sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ if( strcmp(argv[c],"--service") == 0)
+ {
+ WinServiceRun();
+ }
+ ////
+ #endif
+ ++c;
+ }
+
+ if (!sConfig.SetSource(cfg_file))
+ {
+ sLog.outError("Could not find configuration file %s.", cfg_file);
+ return 1;
+ }
+ sLog.outString("Using configuration file %s.", cfg_file);
+
+ uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
+ if (confVersion < _TRINITY_CORE_CONFVER)
+ {
+ sLog.outError("*****************************************************************************");
+ sLog.outError(" WARNING: Your trinitycore.conf version indicates your conf file is out of date!");
+ sLog.outError(" Please check for updates, as your current default values may cause");
+ sLog.outError(" strange behavior.");
+ sLog.outError("*****************************************************************************");
+ clock_t pause = 3000 + clock();
+
+ while (pause > clock()) {}
+ }
+
+ ///- and run the 'Master'
+ /// \todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd?
+ return sMaster.Run();
+
+ // at sMaster return function exist with codes
+ // 0 - normal shutdown
+ // 1 - shutdown at error
+ // 2 - restart command used, this code can be used by restarter for restart Trinityd
+}
+
+/// @}
diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp
new file mode 100644
index 00000000000..c1484fede8e
--- /dev/null
+++ b/src/trinitycore/Master.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup Trinityd
+*/
+
+#include <ace/OS_NS_signal.h>
+
+#include "WorldSocketMgr.h"
+#include "Common.h"
+#include "Master.h"
+#include "WorldSocket.h"
+#include "WorldRunnable.h"
+#include "World.h"
+#include "Log.h"
+#include "Timer.h"
+#include "Policies/SingletonImp.h"
+#include "SystemConfig.h"
+#include "Config/ConfigEnv.h"
+#include "Database/DatabaseEnv.h"
+#include "CliRunnable.h"
+#include "RASocket.h"
+#include "ScriptCalls.h"
+#include "Util.h"
+
+#include "sockets/TcpSocket.h"
+#include "sockets/Utility.h"
+#include "sockets/Parse.h"
+#include "sockets/Socket.h"
+#include "sockets/SocketHandler.h"
+#include "sockets/ListenSocket.h"
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+extern int m_ServiceStatus;
+#endif
+
+/// \todo Warning disabling not useful under VC++2005. Can somebody say on which compiler it is useful?
+#pragma warning(disable:4305)
+
+INSTANTIATE_SINGLETON_1( Master );
+
+volatile uint32 Master::m_masterLoopCounter = 0;
+
+class FreezeDetectorRunnable : public ZThread::Runnable
+{
+public:
+ FreezeDetectorRunnable() { _delaytime = 0; }
+ uint32 m_loops, m_lastchange;
+ uint32 w_loops, w_lastchange;
+ uint32 _delaytime;
+ void SetDelayTime(uint32 t) { _delaytime = t; }
+ void run(void)
+ {
+ if(!_delaytime)
+ return;
+ sLog.outString("Starting up anti-freeze thread (%u seconds max stuck time)...",_delaytime/1000);
+ m_loops = 0;
+ w_loops = 0;
+ m_lastchange = 0;
+ w_lastchange = 0;
+ while(!World::IsStopped())
+ {
+ ZThread::Thread::sleep(1000);
+ uint32 curtime = getMSTime();
+ //DEBUG_LOG("anti-freeze: time=%u, counters=[%u; %u]",curtime,Master::m_masterLoopCounter,World::m_worldLoopCounter);
+
+ // There is no Master anymore
+ // TODO: clear the rest of the code
+// // normal work
+// if(m_loops != Master::m_masterLoopCounter)
+// {
+// m_lastchange = curtime;
+// m_loops = Master::m_masterLoopCounter;
+// }
+// // possible freeze
+// else if(getMSTimeDiff(m_lastchange,curtime) > _delaytime)
+// {
+// sLog.outError("Main/Sockets Thread hangs, kicking out server!");
+// *((uint32 volatile*)NULL) = 0; // bang crash
+// }
+
+ // normal work
+ if(w_loops != World::m_worldLoopCounter)
+ {
+ w_lastchange = curtime;
+ w_loops = World::m_worldLoopCounter;
+ }
+ // possible freeze
+ else if(getMSTimeDiff(w_lastchange,curtime) > _delaytime)
+ {
+ sLog.outError("World Thread hangs, kicking out server!");
+ *((uint32 volatile*)NULL) = 0; // bang crash
+ }
+ }
+ sLog.outString("Anti-freeze thread exiting without problems.");
+ }
+};
+
+class RARunnable : public ZThread::Runnable
+{
+public:
+ uint32 numLoops, loopCounter;
+
+ RARunnable ()
+ {
+ uint32 socketSelecttime = sWorld.getConfig (CONFIG_SOCKET_SELECTTIME);
+ numLoops = (sConfig.GetIntDefault ("MaxPingTime", 30) * (MINUTE * 1000000 / socketSelecttime));
+ loopCounter = 0;
+ }
+
+ void
+ checkping ()
+ {
+ // ping if need
+ if ((++loopCounter) == numLoops)
+ {
+ loopCounter = 0;
+ sLog.outDetail ("Ping MySQL to keep connection alive");
+ delete WorldDatabase.Query ("SELECT 1 FROM command LIMIT 1");
+ delete LoginDatabase.Query ("SELECT 1 FROM realmlist LIMIT 1");
+ delete CharacterDatabase.Query ("SELECT 1 FROM bugreport LIMIT 1");
+ }
+ }
+
+ void
+ run (void)
+ {
+ SocketHandler h;
+
+ // Launch the RA listener socket
+ ListenSocket<RASocket> RAListenSocket (h);
+ bool usera = sConfig.GetBoolDefault ("Ra.Enable", false);
+
+ if (usera)
+ {
+ port_t raport = sConfig.GetIntDefault ("Ra.Port", 3443);
+ std::string stringip = sConfig.GetStringDefault ("Ra.IP", "0.0.0.0");
+ ipaddr_t raip;
+ if (!Utility::u2ip (stringip, raip))
+ sLog.outError ("Trinity RA can not bind to ip %s", stringip.c_str ());
+ else if (RAListenSocket.Bind (raip, raport))
+ sLog.outError ("Trinity RA can not bind to port %d on %s", raport, stringip.c_str ());
+ else
+ {
+ h.Add (&RAListenSocket);
+
+ sLog.outString ("Starting Remote access listner on port %d on %s", raport, stringip.c_str ());
+ }
+ }
+
+ // Socket Selet time is in microseconds , not miliseconds!!
+ uint32 socketSelecttime = sWorld.getConfig (CONFIG_SOCKET_SELECTTIME);
+
+ // if use ra spend time waiting for io, if not use ra ,just sleep
+ if (usera)
+ while (!World::IsStopped())
+ {
+ h.Select (0, socketSelecttime);
+ checkping ();
+ }
+ else
+ while (!World::IsStopped())
+ {
+ ZThread::Thread::sleep (static_cast<unsigned long> (socketSelecttime / 1000));
+ checkping ();
+ }
+ }
+};
+
+Master::Master()
+{
+}
+
+Master::~Master()
+{
+}
+
+/// Main function
+int Master::Run()
+{
+ sLog.outString( "%s (core-daemon)", _FULLVERSION );
+ sLog.outString( "<Ctrl-C> to stop.\n" );
+
+ sLog.outTitle( " ______ __");
+ sLog.outTitle( "/\\__ _\\ __ __/\\ \\__");
+ sLog.outTitle( "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\ ,_\\ __ __");
+ sLog.outTitle( " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\");
+ sLog.outTitle( " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\");
+ sLog.outTitle( " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\");
+ sLog.outTitle( " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\");
+ sLog.outTitle( " C O R E /\\___/");
+ sLog.outTitle( "http://TrinityCore.org \\/__/\n");
+
+ /// worldd PID file creation
+ std::string pidfile = sConfig.GetStringDefault("PidFile", "");
+ if(!pidfile.empty())
+ {
+ uint32 pid = CreatePIDFile(pidfile);
+ if( !pid )
+ {
+ sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() );
+ return 1;
+ }
+
+ sLog.outString( "Daemon PID: %u\n", pid );
+ }
+
+ ///- Start the databases
+ if (!_StartDB())
+ return 1;
+
+ ///- Initialize the World
+ sWorld.SetInitialWorldSettings();
+
+ ///- Catch termination signals
+ _HookSignals();
+
+ ///- Launch WorldRunnable thread
+ ZThread::Thread t(new WorldRunnable);
+ t.setPriority ((ZThread::Priority )2);
+
+ // set server online
+ LoginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID);
+
+#ifdef WIN32
+ if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
+#else
+ if (sConfig.GetBoolDefault("Console.Enable", true))
+#endif
+ {
+ ///- Launch CliRunnable thread
+ ZThread::Thread td1(new CliRunnable);
+ }
+
+ ZThread::Thread td2(new RARunnable);
+
+ ///- Handle affinity for multiple processors and process priority on Windows
+ #ifdef WIN32
+ {
+ HANDLE hProcess = GetCurrentProcess();
+
+ uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
+ if(Aff > 0)
+ {
+ ULONG_PTR appAff;
+ ULONG_PTR sysAff;
+
+ if(GetProcessAffinityMask(hProcess,&appAff,&sysAff))
+ {
+ ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
+
+ if(!curAff )
+ {
+ sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for Trinityd. Accessible processors bitmask (hex): %x",Aff,appAff);
+ }
+ else
+ {
+ if(SetProcessAffinityMask(hProcess,curAff))
+ sLog.outString("Using processors (bitmask, hex): %x", curAff);
+ else
+ sLog.outError("Can't set used processors (hex): %x",curAff);
+ }
+ }
+ sLog.outString();
+ }
+
+ bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
+
+// if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/)
+ if(Prio)
+ {
+ if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
+ sLog.outString("TrinityCore process priority class set to HIGH");
+ else
+ sLog.outError("ERROR: Can't set Trinityd process priority class.");
+ sLog.outString();
+ }
+ }
+ #endif
+
+ uint32 realCurrTime, realPrevTime;
+ realCurrTime = realPrevTime = getMSTime();
+
+ uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME);
+
+ // maximum counter for next ping
+ uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / socketSelecttime));
+ uint32 loopCounter = 0;
+
+ ///- Start up freeze catcher thread
+ uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0);
+ if(freeze_delay)
+ {
+ FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable();
+ fdr->SetDelayTime(freeze_delay*1000);
+ ZThread::Thread t(fdr);
+ t.setPriority(ZThread::High);
+ }
+
+ ///- Launch the world listener socket
+ port_t wsport = sWorld.getConfig (CONFIG_PORT_WORLD);
+ std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0");
+
+ if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1)
+ {
+ sLog.outError ("Failed to start network");
+ World::StopNow(ERROR_EXIT_CODE);
+ // go down and shutdown the server
+ }
+
+ sWorldSocketMgr->Wait ();
+
+ // set server offline
+ LoginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID);
+
+ ///- Remove signal handling before leaving
+ _UnhookSignals();
+
+ // when the main thread closes the singletons get unloaded
+ // since worldrunnable uses them, it will crash if unloaded after master
+ t.wait();
+ td2.wait ();
+
+ ///- Clean database before leaving
+ clearOnlineAccounts();
+
+ ///- Wait for delay threads to end
+ CharacterDatabase.HaltDelayThread();
+ WorldDatabase.HaltDelayThread();
+ LoginDatabase.HaltDelayThread();
+
+ sLog.outString( "Halting process..." );
+
+ #ifdef WIN32
+ if (sConfig.GetBoolDefault("Console.Enable", true))
+ {
+ // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API)
+ //_exit(1);
+ // send keyboard input to safely unblock the CLI thread
+ INPUT_RECORD b[5];
+ HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ b[0].EventType = KEY_EVENT;
+ b[0].Event.KeyEvent.bKeyDown = TRUE;
+ b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
+ b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
+ b[0].Event.KeyEvent.wRepeatCount = 1;
+
+ b[1].EventType = KEY_EVENT;
+ b[1].Event.KeyEvent.bKeyDown = FALSE;
+ b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
+ b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
+ b[1].Event.KeyEvent.wRepeatCount = 1;
+
+ b[2].EventType = KEY_EVENT;
+ b[2].Event.KeyEvent.bKeyDown = TRUE;
+ b[2].Event.KeyEvent.dwControlKeyState = 0;
+ b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
+ b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
+ b[2].Event.KeyEvent.wRepeatCount = 1;
+ b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
+
+ b[3].EventType = KEY_EVENT;
+ b[3].Event.KeyEvent.bKeyDown = FALSE;
+ b[3].Event.KeyEvent.dwControlKeyState = 0;
+ b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
+ b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
+ b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
+ b[3].Event.KeyEvent.wRepeatCount = 1;
+ DWORD numb;
+ BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb);
+ }
+ #endif
+
+ // for some unknown reason, unloading scripts here and not in worldrunnable
+ // fixes a memory leak related to detaching threads from the module
+ UnloadScriptingModule();
+
+ // Exit the process with specified return value
+ return World::GetExitCode();
+}
+
+/// Initialize connection to the databases
+bool Master::_StartDB()
+{
+ ///- Get world database info from configuration file
+ std::string dbstring;
+ if(!sConfig.GetString("WorldDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Database not specified in configuration file");
+ return false;
+ }
+ sLog.outString("World Database: %s", dbstring.c_str());
+
+ ///- Initialise the world database
+ if(!WorldDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to world database %s",dbstring.c_str());
+ return false;
+ }
+
+ if(!sConfig.GetString("CharacterDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Character Database not specified in configuration file");
+ return false;
+ }
+ sLog.outString("Character Database: %s", dbstring.c_str());
+
+ ///- Initialise the Character database
+ if(!CharacterDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to Character database %s",dbstring.c_str());
+ return false;
+ }
+
+ ///- Get login database info from configuration file
+ if(!sConfig.GetString("LoginDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Login database not specified in configuration file");
+ return false;
+ }
+
+ ///- Initialise the login database
+ sLog.outString("Login Database: %s", dbstring.c_str() );
+ if(!LoginDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to login database %s",dbstring.c_str());
+ return false;
+ }
+
+ ///- Get the realm Id from the configuration file
+ realmID = sConfig.GetIntDefault("RealmID", 0);
+ if(!realmID)
+ {
+ sLog.outError("Realm ID not defined in configuration file");
+ return false;
+ }
+ sLog.outString("Realm running as realm ID %d", realmID);
+
+ ///- Clean the database before starting
+ clearOnlineAccounts();
+
+ sWorld.LoadDBVersion();
+
+ sLog.outString("Using %s", sWorld.GetDBVersion());
+ return true;
+}
+
+/// Clear 'online' status for all accounts with characters in this realm
+void Master::clearOnlineAccounts()
+{
+ // Cleanup online status for characters hosted at current realm
+ /// \todo Only accounts with characters logged on *this* realm should have online status reset. Move the online column from 'account' to 'realmcharacters'?
+ LoginDatabase.PExecute(
+ "UPDATE account SET online = 0 WHERE online > 0 "
+ "AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = '%d')",realmID);
+
+
+ CharacterDatabase.Execute("UPDATE characters SET online = 0 WHERE online<>0");
+}
+
+/// Handle termination signals
+void Master::_OnSignal(int s)
+{
+ switch (s)
+ {
+ case SIGINT:
+ World::StopNow(RESTART_EXIT_CODE);
+ break;
+ case SIGTERM:
+ #ifdef _WIN32
+ case SIGBREAK:
+ #endif
+ World::StopNow(SHUTDOWN_EXIT_CODE);
+ break;
+ }
+
+ signal(s, _OnSignal);
+}
+
+/// Define hook '_OnSignal' for all termination signals
+void Master::_HookSignals()
+{
+ signal(SIGINT, _OnSignal);
+ signal(SIGTERM, _OnSignal);
+ #ifdef _WIN32
+ signal(SIGBREAK, _OnSignal);
+ #endif
+}
+
+/// Unhook the signals before leaving
+void Master::_UnhookSignals()
+{
+ signal(SIGINT, 0);
+ signal(SIGTERM, 0);
+ #ifdef _WIN32
+ signal(SIGBREAK, 0);
+ #endif
+}
diff --git a/src/trinitycore/RASocket.cpp b/src/trinitycore/RASocket.cpp
new file mode 100644
index 00000000000..cfc50d95f89
--- /dev/null
+++ b/src/trinitycore/RASocket.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup Trinityd
+*/
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Log.h"
+#include "RASocket.h"
+#include "World.h"
+#include "Config/ConfigEnv.h"
+#include "Util.h"
+#include "AccountMgr.h"
+
+/// \todo Make this thread safe if in the future 2 admins should be able to log at the same time.
+SOCKET r;
+
+#define dropclient {Sendf("I'm busy right now, come back later."); \
+ SetCloseAndDelete(); \
+ return; \
+ }
+
+uint32 iSession=0; ///< Session number (incremented each time a new connection is made)
+unsigned int iUsers=0; ///< Number of active administrators
+
+typedef int(* pPrintf)(const char*,...);
+
+void ParseCommand(CliCommandHolder::Print*, char*command);
+
+/// RASocket constructor
+RASocket::RASocket(ISocketHandler &h): TcpSocket(h)
+{
+
+ ///- Increment the session number
+ iSess =iSession++ ;
+
+ ///- Get the config parameters
+ bSecure = sConfig.GetBoolDefault( "RA.Secure", true );
+ iMinLevel = sConfig.GetIntDefault( "RA.MinLevel", 3 );
+
+ ///- Initialize buffer and data
+ iInputLength=0;
+ buff=new char[RA_BUFF_SIZE];
+ stage=NONE;
+}
+
+/// RASocket destructor
+RASocket::~RASocket()
+{
+ ///- Delete buffer and decrease active admins count
+ delete [] buff;
+
+ sLog.outRALog("Connection was closed.\n");
+
+ if(stage==OK)
+ iUsers--;
+}
+
+/// Accept an incoming connection
+void RASocket::OnAccept()
+{
+ std::string ss=GetRemoteAddress();
+ sLog.outRALog("Incoming connection from %s.\n",ss.c_str());
+ ///- If there is already an active admin, drop the connection
+ if(iUsers)
+ dropclient
+
+ ///- Else print Motd
+ Sendf("%s\r\n",sWorld.GetMotd());
+}
+
+/// Read data from the network
+void RASocket::OnRead()
+{
+ ///- Read data and check input length
+ TcpSocket::OnRead();
+
+ unsigned int sz=ibuf.GetLength();
+ if(iInputLength+sz>=RA_BUFF_SIZE)
+ {
+ sLog.outRALog("Input buffer overflow, possible DOS attack.\n");
+ SetCloseAndDelete();
+ return;
+ }
+
+ ///- If there is already an active admin (other than you), drop the connection
+ if(stage!=OK && iUsers)
+ dropclient
+
+ char *inp = new char [sz+1];
+ ibuf.Read(inp,sz);
+
+ /// \todo Can somebody explain this 'Linux bugfix'?
+ if(stage==NONE)
+ if(sz>4) //linux remote telnet
+ if(memcmp(inp ,"USER ",5))
+ {
+ delete [] inp;return;
+ printf("lin bugfix");
+ } //linux bugfix
+
+ ///- Discard data after line break or line feed
+ bool gotenter=false;
+ unsigned int y=0;
+ for(;y<sz;y++)
+ if(inp[y]=='\r'||inp[y]=='\n')
+ {
+ gotenter=true;
+ break;
+ }
+
+ //No buffer overflow (checked above)
+ memcpy(&buff[iInputLength],inp,y);
+ iInputLength+=y;
+ delete [] inp;
+ if(gotenter)
+ {
+
+ buff[iInputLength]=0;
+ iInputLength=0;
+ switch(stage)
+ {
+ /// <ul> <li> If the input is 'USER <username>'
+ case NONE:
+ if(!memcmp(buff,"USER ",5)) //got "USER" cmd
+ {
+ szLogin=&buff[5];
+
+ ///- Get the gmlevel and password from the account table
+ std::string login = szLogin;
+
+ ///- Convert Account name to Upper Format
+ AccountMgr::normilizeString(login);
+
+ ///- Escape the Login to allow quotes in names
+ LoginDatabase.escape_string(login);
+
+ QueryResult* result = LoginDatabase.PQuery("SELECT gmlevel FROM account WHERE username = '%s'",login.c_str());
+
+ ///- If the user is not found, deny access
+ if(!result)
+ {
+ Sendf("-No such user.\r\n");
+ sLog.outRALog("User %s does not exist.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ else
+ {
+ Field *fields = result->Fetch();
+
+ //szPass=fields[0].GetString();
+
+ ///- if gmlevel is too low, deny access
+ if(fields[0].GetUInt32()<iMinLevel)
+ {
+ Sendf("-Not enough privileges.\r\n");
+ sLog.outRALog("User %s has no privilege.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ } else
+ {
+ stage=LG;
+ }
+ delete result;
+ }
+ }
+ break;
+ ///<li> If the input is 'PASS <password>' (and the user already gave his username)
+ case LG:
+ if(!memcmp(buff,"PASS ",5)) //got "PASS" cmd
+ { //login+pass ok
+ ///- If password is correct, increment the number of active administrators
+ std::string login = szLogin;
+ std::string pw = &buff[5];
+
+ AccountMgr::normilizeString(login);
+ AccountMgr::normilizeString(pw);
+ LoginDatabase.escape_string(login);
+ LoginDatabase.escape_string(pw);
+
+ QueryResult *check = LoginDatabase.PQuery(
+ "SELECT 1 FROM account WHERE username = '%s' AND sha_pass_hash=SHA1(CONCAT(username,':','%s'))",
+ login.c_str(), pw.c_str());
+
+ if(check)
+ {
+ delete check;
+ r=GetSocket();
+ stage=OK;
+ ++iUsers;
+
+ Sendf("+Logged in.\r\n");
+ sLog.outRALog("User %s has logged in.\n",szLogin.c_str());
+ Sendf("TC>");
+ }
+ else
+ {
+ ///- Else deny access
+ Sendf("-Wrong pass.\r\n");
+ sLog.outRALog("User %s has failed to log in.\n",szLogin.c_str());
+ if(bSecure)SetCloseAndDelete();
+ }
+ }
+ break;
+ ///<li> If user is logged, parse and execute the command
+ case OK:
+ if(strlen(buff))
+ {
+ sLog.outRALog("Got '%s' cmd.\n",buff);
+ sWorld.QueueCliCommand(&RASocket::zprint , buff);
+ }
+ else
+ Sendf("TC>");
+ break;
+ ///</ul>
+ };
+
+ }
+}
+
+/// Output function
+void RASocket::zprint( const char * szText )
+{
+ if( !szText )
+ return;
+
+ #ifdef RA_CRYPT
+
+ char *megabuffer=strdup(szText);
+ unsigned int sz=strlen(megabuffer);
+ Encrypt(megabuffer,sz);
+ send(r,megabuffer,sz,0);
+ delete [] megabuffer;
+
+ #else
+
+ unsigned int sz=strlen(szText);
+ send(r,szText,sz,0);
+
+ #endif
+}
diff --git a/src/trinityrealm/AuthSocket.cpp b/src/trinityrealm/AuthSocket.cpp
new file mode 100644
index 00000000000..6f8363a9724
--- /dev/null
+++ b/src/trinityrealm/AuthSocket.cpp
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup realmd
+*/
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "ByteBuffer.h"
+#include "Config/ConfigEnv.h"
+#include "Log.h"
+#include "RealmList.h"
+#include "AuthSocket.h"
+#include "AuthCodes.h"
+#include <openssl/md5.h>
+#include "Auth/Sha1.h"
+//#include "Util.h" -- for commented utf8ToUpperOnlyLatin
+
+extern RealmList m_realmList;
+
+extern DatabaseType LoginDatabase;
+
+#define ChunkSize 2048
+
+enum eAuthCmd
+{
+ //AUTH_NO_CMD = 0xFF,
+ AUTH_LOGON_CHALLENGE = 0x00,
+ AUTH_LOGON_PROOF = 0x01,
+ AUTH_RECONNECT_CHALLENGE = 0x02,
+ AUTH_RECONNECT_PROOF = 0x03,
+ //update srv =4
+ REALM_LIST = 0x10,
+ XFER_INITIATE = 0x30,
+ XFER_DATA = 0x31,
+ XFER_ACCEPT = 0x32,
+ XFER_RESUME = 0x33,
+ XFER_CANCEL = 0x34
+};
+
+enum eStatus
+{
+ STATUS_CONNECTED = 0,
+ STATUS_AUTHED
+};
+
+// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some paltform
+#if defined( __GNUC__ )
+#pragma pack(1)
+#else
+#pragma pack(push,1)
+#endif
+
+typedef struct AUTH_LOGON_CHALLENGE_C
+{
+ uint8 cmd;
+ uint8 error;
+ uint16 size;
+ uint8 gamename[4];
+ uint8 version1;
+ uint8 version2;
+ uint8 version3;
+ uint16 build;
+ uint8 platform[4];
+ uint8 os[4];
+ uint8 country[4];
+ uint32 timezone_bias;
+ uint32 ip;
+ uint8 I_len;
+ uint8 I[1];
+} sAuthLogonChallenge_C;
+
+//typedef sAuthLogonChallenge_C sAuthReconnectChallenge_C;
+/*
+typedef struct
+{
+ uint8 cmd;
+ uint8 error;
+ uint8 unk2;
+ uint8 B[32];
+ uint8 g_len;
+ uint8 g[1];
+ uint8 N_len;
+ uint8 N[32];
+ uint8 s[32];
+ uint8 unk3[16];
+} sAuthLogonChallenge_S;
+*/
+
+typedef struct AUTH_LOGON_PROOF_C
+{
+ uint8 cmd;
+ uint8 A[32];
+ uint8 M1[20];
+ uint8 crc_hash[20];
+ uint8 number_of_keys;
+ uint8 unk; // Added in 1.12.x client branch
+} sAuthLogonProof_C;
+/*
+typedef struct
+{
+ uint16 unk1;
+ uint32 unk2;
+ uint8 unk3[4];
+ uint16 unk4[20];
+} sAuthLogonProofKey_C;
+*/
+typedef struct AUTH_LOGON_PROOF_S
+{
+ uint8 cmd;
+ uint8 error;
+ uint8 M2[20];
+ uint32 unk1;
+ uint32 unk2;
+ uint16 unk3;
+} sAuthLogonProof_S;
+
+typedef struct AUTH_RECONNECT_PROOF_C
+{
+ uint8 cmd;
+ uint8 R1[16];
+ uint8 R2[20];
+ uint8 R3[20];
+ uint8 number_of_keys;
+} sAuthReconnectProof_C;
+
+typedef struct XFER_INIT
+{
+ uint8 cmd; // XFER_INITIATE
+ uint8 fileNameLen; // strlen(fileName);
+ uint8 fileName[5]; // fileName[fileNameLen]
+ uint64 file_size; // file size (bytes)
+ uint8 md5[MD5_DIGEST_LENGTH]; // MD5
+}XFER_INIT;
+
+typedef struct XFER_DATA
+{
+ uint8 opcode;
+ uint16 data_size;
+ uint8 data[ChunkSize];
+}XFER_DATA_STRUCT;
+
+typedef struct AuthHandler
+{
+ eAuthCmd cmd;
+ uint32 status;
+ bool (AuthSocket::*handler)(void);
+}AuthHandler;
+
+// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform
+#if defined( __GNUC__ )
+#pragma pack()
+#else
+#pragma pack(pop)
+#endif
+
+/// Launch a thread to transfer a patch to the client
+class PatcherRunnable: public ZThread::Runnable
+{
+ public:
+ PatcherRunnable(class AuthSocket *);
+ void run();
+
+ private:
+ AuthSocket * mySocket;
+};
+
+typedef struct PATCH_INFO
+{
+ uint8 md5[MD5_DIGEST_LENGTH];
+}PATCH_INFO;
+
+/// Caches MD5 hash of client patches present on the server
+class Patcher
+{
+ public:
+ typedef std::map<std::string, PATCH_INFO*> Patches;
+ ~Patcher();
+ Patcher();
+ Patches::const_iterator begin() const { return _patches.begin(); }
+ Patches::const_iterator end() const { return _patches.end(); }
+ void LoadPatchMD5(char*);
+ bool GetHash(char * pat,uint8 mymd5[16]);
+
+ private:
+ void LoadPatchesInfo();
+ Patches _patches;
+};
+
+const AuthHandler table[] =
+{
+ { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge },
+ { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof },
+ { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge},
+ { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof },
+ { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList },
+ { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept },
+ { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume },
+ { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel }
+};
+
+#define AUTH_TOTAL_COMMANDS sizeof(table)/sizeof(AuthHandler)
+
+///Holds the MD5 hash of client patches present on the server
+Patcher PatchesCache;
+
+/// Constructor - set the N and g values for SRP6
+AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h)
+{
+ N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
+ g.SetDword(7);
+ _authed = false;
+ pPatch = NULL;
+
+ _accountSecurityLevel = SEC_PLAYER;
+}
+
+/// Close patch file descriptor before leaving
+AuthSocket::~AuthSocket()
+{
+ ZThread::Guard<ZThread::Mutex> g(patcherLock);
+ if(pPatch)
+ fclose(pPatch);
+}
+
+/// Accept the connection and set the s random value for SRP6
+void AuthSocket::OnAccept()
+{
+ sLog.outBasic("Accepting connection from '%s:%d'",
+ GetRemoteAddress().c_str(), GetRemotePort());
+
+ s.SetRand(s_BYTE_SIZE * 8);
+}
+
+/// Read the packet from the client
+void AuthSocket::OnRead()
+{
+ ///- Read the packet
+ TcpSocket::OnRead();
+ uint8 _cmd;
+ while (1)
+ {
+ if (!ibuf.GetLength())
+ return;
+
+ ///- Get the command out of it
+ ibuf.SoftRead((char *)&_cmd, 1); // UQ1: No longer exists in new net code ???
+ //ibuf.Read((char *)&_cmd, 1);
+ /*char *command = (char *)malloc(1);
+
+ ibuf.Read(command, 1);
+
+ _cmd = (uint8)command;*/
+ // assert(0);
+ size_t i;
+
+ ///- Circle through known commands and call the correct command handler
+ for (i=0;i<AUTH_TOTAL_COMMANDS; i++)
+ {
+ if ((uint8)table[i].cmd == _cmd &&
+ (table[i].status == STATUS_CONNECTED ||
+ (_authed && table[i].status == STATUS_AUTHED)))
+ {
+ DEBUG_LOG("[Auth] got data for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength());
+
+ if (!(*this.*table[i].handler)())
+ {
+ DEBUG_LOG("Command handler failed for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength());
+ return;
+ }
+ break;
+ }
+ }
+
+ ///- Report unknown commands in the debug log
+ if (i==AUTH_TOTAL_COMMANDS)
+ {
+ DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd);
+ return;
+ }
+ }
+}
+
+/// Make the SRP6 calculation from hash in dB
+void AuthSocket::_SetVSFields(const std::string& rI)
+{
+ BigNumber I;
+ I.SetHexStr(rI.c_str());
+
+ //In case of leading zeroes in the rI hash, restore them
+ uint8 mDigest[SHA_DIGEST_LENGTH];
+ memset(mDigest,0,SHA_DIGEST_LENGTH);
+ if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
+ memcpy(mDigest,I.AsByteArray(),I.GetNumBytes());
+
+ std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH);
+
+ Sha1Hash sha;
+ sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
+ sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
+ sha.Finalize();
+ BigNumber x;
+ x.SetBinary(sha.GetDigest(), sha.GetLength());
+ v = g.ModExp(x, N);
+ // No SQL injection (username escaped)
+ const char *v_hex, *s_hex;
+ v_hex = v.AsHexStr();
+ s_hex = s.AsHexStr();
+ LoginDatabase.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'",v_hex,s_hex, _safelogin.c_str() );
+ OPENSSL_free((void*)v_hex);
+ OPENSSL_free((void*)s_hex);
+}
+
+/// Logon Challenge command handler
+bool AuthSocket::_HandleLogonChallenge()
+{
+ DEBUG_LOG("Entering _HandleLogonChallenge");
+ if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C))
+ return false;
+
+ ///- Read the first 4 bytes (header) to get the length of the remaining of the packet
+ std::vector<uint8> buf;
+ buf.resize(4);
+
+ ibuf.Read((char *)&buf[0], 4);
+
+ EndianConvert(*((uint16*)(buf[0])));
+ uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size;
+ DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining);
+
+ if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining))
+ return false;
+
+ //No big fear of memory outage (size is int16, i.e. < 65536)
+ buf.resize(remaining + buf.size() + 1);
+ buf[buf.size() - 1] = 0;
+ sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0];
+
+ // BigEndian code, nop in little endian case
+ // size already converted
+ EndianConvert(*((uint32*)(&ch->gamename[0])));
+ EndianConvert(ch->build);
+ EndianConvert(*((uint32*)(&ch->platform[0])));
+ EndianConvert(*((uint32*)(&ch->os[0])));
+ EndianConvert(*((uint32*)(&ch->country[0])));
+ EndianConvert(ch->timezone_bias);
+ EndianConvert(ch->ip);
+
+ ///- Read the remaining of the packet
+ ibuf.Read((char *)&buf[4], remaining);
+ DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size);
+ DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I);
+
+ ByteBuffer pkt;
+
+ _login = (const char*)ch->I;
+ _build = ch->build;
+
+ ///- Normalize account name
+ //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form
+
+ //Escape the user login to avoid further SQL injection
+ //Memory will be freed on AuthSocket object destruction
+ _safelogin=_login;
+ LoginDatabase.escape_string(_safelogin);
+
+ pkt << (uint8) AUTH_LOGON_CHALLENGE;
+ pkt << (uint8) 0x00;
+
+ ///- Verify that this IP is not in the ip_banned table
+ // No SQL injection possible (paste the IP address as passed by the socket)
+ LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+
+ std::string address = GetRemoteAddress();
+ LoginDatabase.escape_string(address);
+ QueryResult *result = LoginDatabase.PQuery( "SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str());
+ if(result)
+ {
+ pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED;
+ sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ());
+ delete result;
+ }
+ else
+ {
+ ///- Get the account details from the account table
+ // No SQL injection (escaped user name)
+
+ result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel FROM account WHERE username = '%s'",_safelogin.c_str ());
+ if( result )
+ {
+ ///- If the IP is 'locked', check that the player comes indeed from the correct IP address
+ bool locked = false;
+ if((*result)[2].GetUInt8() == 1) // if ip is locked
+ {
+ DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString());
+ DEBUG_LOG("[AuthChallenge] Player address is '%s'", GetRemoteAddress().c_str());
+ if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) )
+ {
+ DEBUG_LOG("[AuthChallenge] Account IP differs");
+ pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
+ locked=true;
+ }
+ else
+ {
+ DEBUG_LOG("[AuthChallenge] Account IP matches");
+ }
+ }
+ else
+ {
+ DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str());
+ }
+
+ if (!locked)
+ {
+ //set expired bans to inactive
+ LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
+ ///- If the account is banned, reject the logon attempt
+ QueryResult *banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32());
+ if(banresult)
+ {
+ if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64())
+ {
+ pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED;
+ sLog.outBasic("[AuthChallenge] Banned account %s tries to login!",_login.c_str ());
+ }
+ else
+ {
+ pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
+ sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!",_login.c_str ());
+ }
+
+ delete banresult;
+ }
+ else
+ {
+ ///- Get the password from the account table, upper it, and make the SRP6 calculation
+ std::string rI = (*result)[0].GetCppString();
+ _SetVSFields(rI);
+
+ b.SetRand(19 * 8);
+ BigNumber gmod=g.ModExp(b, N);
+ B = ((v * 3) + gmod) % N;
+
+ ASSERT(gmod.GetNumBytes() <= 32);
+
+ BigNumber unk3;
+ unk3.SetRand(16*8);
+
+ ///- Fill the response packet with the result
+ pkt << (uint8)REALM_AUTH_SUCCESS;
+
+ // B may be calculated < 32B so we force minnimal length to 32B
+ pkt.append(B.AsByteArray(32), 32); // 32 bytes
+ pkt << (uint8)1;
+ pkt.append(g.AsByteArray(), 1);
+ pkt << (uint8)32;
+ pkt.append(N.AsByteArray(), 32);
+ pkt.append(s.AsByteArray(), s.GetNumBytes()); // 32 bytes
+ pkt.append(unk3.AsByteArray(), 16);
+ pkt << (uint8)0; // Added in 1.12.x client branch
+
+ uint8 secLevel = (*result)[4].GetUInt8();
+ _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
+
+ _localizationName.resize(4);
+ for(int i = 0; i <4; ++i)
+ _localizationName[i] = ch->country[4-i-1];
+
+ sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3],ch->country[2],ch->country[1],ch->country[0], GetLocaleByName(_localizationName));
+ }
+ }
+ delete result;
+ }
+ else //no account
+ {
+ pkt<< (uint8) REALM_AUTH_NO_MATCH;
+ }
+ }
+ SendBuf((char const*)pkt.contents(), pkt.size());
+ return true;
+}
+
+/// Logon Proof command handler
+bool AuthSocket::_HandleLogonProof()
+{
+ DEBUG_LOG("Entering _HandleLogonProof");
+ ///- Read the packet
+ if (ibuf.GetLength() < sizeof(sAuthLogonProof_C))
+ return false;
+ sAuthLogonProof_C lp;
+ ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C));
+
+ ///- Check if the client has one of the expected version numbers
+ bool valid_version=false;
+ int accepted_versions[]=EXPECTED_TRINITY_CLIENT_BUILD;
+ for(int i=0;accepted_versions[i];i++)
+ {
+ if(_build==accepted_versions[i])
+ {
+ valid_version=true;
+ break;
+ }
+ }
+
+ /// <ul><li> If the client has no valid version
+ if(!valid_version)
+ {
+ ///- Check if we have the apropriate patch on the disk
+
+ // 24 = len("./patches/65535enGB.mpq")+1
+ char tmp[24];
+ // No buffer overflow (fixed length of arguments)
+ sprintf(tmp,"./patches/%d%s.mpq",_build, _localizationName.c_str());
+ // This will be closed at the destruction of the AuthSocket (client deconnection)
+ FILE *pFile=fopen(tmp,"rb");
+
+ if(!pFile)
+ {
+ ByteBuffer pkt;
+ pkt << (uint8) AUTH_LOGON_CHALLENGE;
+ pkt << (uint8) 0x00;
+ pkt << (uint8) REALM_AUTH_WRONG_BUILD_NUMBER;
+ DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build);
+ DEBUG_LOG("[AuthChallenge] Patch %s not found",tmp);
+ SendBuf((char const*)pkt.contents(), pkt.size());
+ return true;
+ }
+ else // have patch
+ {
+ pPatch=pFile;
+ XFER_INIT xferh;
+
+ ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it)
+ if(PatchesCache.GetHash(tmp,(uint8*)&xferh.md5))
+ {
+ DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s",tmp);
+ }
+ else
+ { //calculate patch md5
+ printf("\n[AuthChallenge] Patch info for %s was not cached.",tmp);
+ PatchesCache.LoadPatchMD5(tmp);
+ PatchesCache.GetHash(tmp,(uint8*)&xferh.md5);
+ }
+
+ ///- Send a packet to the client with the file length and MD5 hash
+ uint8 data[2]={AUTH_LOGON_PROOF,REALM_AUTH_UPDATE_CLIENT};
+ SendBuf((const char*)data,sizeof(data));
+
+ memcpy(&xferh,"0\x05Patch",7);
+ xferh.cmd=XFER_INITIATE;
+ fseek(pPatch,0,SEEK_END);
+ xferh.file_size=ftell(pPatch);
+
+ SendBuf((const char*)&xferh,sizeof(xferh));
+ return true;
+ }
+ }
+ /// </ul>
+
+ ///- Continue the SRP6 calculation based on data received from the client
+ BigNumber A;
+ A.SetBinary(lp.A, 32);
+
+ Sha1Hash sha;
+ sha.UpdateBigNumbers(&A, &B, NULL);
+ sha.Finalize();
+ BigNumber u;
+ u.SetBinary(sha.GetDigest(), 20);
+ BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);
+
+ uint8 t[32];
+ uint8 t1[16];
+ uint8 vK[40];
+ memcpy(t, S.AsByteArray(), 32);
+ for (int i = 0; i < 16; i++)
+ {
+ t1[i] = t[i*2];
+ }
+ sha.Initialize();
+ sha.UpdateData(t1, 16);
+ sha.Finalize();
+ for (int i = 0; i < 20; i++)
+ {
+ vK[i*2] = sha.GetDigest()[i];
+ }
+ for (int i = 0; i < 16; i++)
+ {
+ t1[i] = t[i*2+1];
+ }
+ sha.Initialize();
+ sha.UpdateData(t1, 16);
+ sha.Finalize();
+ for (int i = 0; i < 20; i++)
+ {
+ vK[i*2+1] = sha.GetDigest()[i];
+ }
+ K.SetBinary(vK, 40);
+
+ uint8 hash[20];
+
+ sha.Initialize();
+ sha.UpdateBigNumbers(&N, NULL);
+ sha.Finalize();
+ memcpy(hash, sha.GetDigest(), 20);
+ sha.Initialize();
+ sha.UpdateBigNumbers(&g, NULL);
+ sha.Finalize();
+ for (int i = 0; i < 20; i++)
+ {
+ hash[i] ^= sha.GetDigest()[i];
+ }
+ BigNumber t3;
+ t3.SetBinary(hash, 20);
+
+ sha.Initialize();
+ sha.UpdateData(_login);
+ sha.Finalize();
+ uint8 t4[SHA_DIGEST_LENGTH];
+ memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);
+
+ sha.Initialize();
+ sha.UpdateBigNumbers(&t3, NULL);
+ sha.UpdateData(t4, SHA_DIGEST_LENGTH);
+ sha.UpdateBigNumbers(&s, &A, &B, &K, NULL);
+ sha.Finalize();
+ BigNumber M;
+ M.SetBinary(sha.GetDigest(), 20);
+
+ ///- Check if SRP6 results match (password is correct), else send an error
+ if (!memcmp(M.AsByteArray(), lp.M1, 20))
+ {
+ sLog.outBasic("User '%s' successfully authenticated", _login.c_str());
+
+ ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
+ // No SQL injection (escaped user name) and IP address as received by socket
+ const char* K_hex = K.AsHexStr();
+ LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str() );
+ OPENSSL_free((void*)K_hex);
+
+ ///- Finish SRP6 and send the final result to the client
+ sha.Initialize();
+ sha.UpdateBigNumbers(&A, &M, &K, NULL);
+ sha.Finalize();
+
+ sAuthLogonProof_S proof;
+ memcpy(proof.M2, sha.GetDigest(), 20);
+ proof.cmd = AUTH_LOGON_PROOF;
+ proof.error = 0;
+ proof.unk1 = 0x00800000;
+ proof.unk2 = 0x00;
+ proof.unk3 = 0x00;
+
+ SendBuf((char *)&proof, sizeof(proof));
+
+ ///- Set _authed to true!
+ _authed = true;
+ }
+ else
+ {
+ char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0};
+ SendBuf(data,sizeof(data));
+ sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ());
+
+ uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0);
+ if(MaxWrongPassCount > 0)
+ {
+ //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
+ LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '%s'",_safelogin.c_str());
+
+ if(QueryResult *loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '%s'", _safelogin.c_str()))
+ {
+ Field* fields = loginfail->Fetch();
+ uint32 failed_logins = fields[1].GetUInt32();
+
+ if( failed_logins >= MaxWrongPassCount )
+ {
+ uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600);
+ bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false);
+
+ if(WrongPassBanType)
+ {
+ uint32 acc_id = fields[0].GetUInt32();
+ LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban',1)",
+ acc_id, WrongPassBanTime);
+ sLog.outBasic("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times",
+ _login.c_str(), WrongPassBanTime, failed_logins);
+ }
+ else
+ {
+ std::string current_ip = GetRemoteAddress();
+ LoginDatabase.escape_string(current_ip);
+ LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban')",
+ current_ip.c_str(), WrongPassBanTime);
+ sLog.outBasic("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times",
+ current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
+ }
+ }
+ delete loginfail;
+ }
+ }
+ }
+ return true;
+}
+
+/// Reconnect Challenge command handler
+bool AuthSocket::_HandleReconnectChallenge()
+{
+ DEBUG_LOG("Entering _HandleReconnectChallenge");
+ if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C))
+ return false;
+
+ ///- Read the first 4 bytes (header) to get the length of the remaining of the packet
+ std::vector<uint8> buf;
+ buf.resize(4);
+
+ ibuf.Read((char *)&buf[0], 4);
+
+ EndianConvert(*((uint16*)(buf[0])));
+ uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size;
+ DEBUG_LOG("[ReconnectChallenge] got header, body is %#04x bytes", remaining);
+
+ if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining))
+ return false;
+
+ //No big fear of memory outage (size is int16, i.e. < 65536)
+ buf.resize(remaining + buf.size() + 1);
+ buf[buf.size() - 1] = 0;
+ sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0];
+
+ ///- Read the remaining of the packet
+ ibuf.Read((char *)&buf[4], remaining);
+ DEBUG_LOG("[ReconnectChallenge] got full packet, %#04x bytes", ch->size);
+ DEBUG_LOG("[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I);
+
+ _login = (const char*)ch->I;
+ _safelogin = _login;
+
+ QueryResult *result = LoginDatabase.PQuery ("SELECT sessionkey FROM account WHERE username = '%s'", _safelogin.c_str ());
+
+ // Stop if the account is not found
+ if (!result)
+ {
+ sLog.outError("[ERROR] user %s tried to login and we cannot find his session key in the database.", _login.c_str());
+ SetCloseAndDelete();
+ return false;
+ }
+
+ Field* fields = result->Fetch ();
+ K.SetHexStr (fields[0].GetString ());
+ delete result;
+
+ ///- Sending response
+ ByteBuffer pkt;
+ pkt << (uint8) AUTH_RECONNECT_CHALLENGE;
+ pkt << (uint8) 0x00;
+ _reconnectProof.SetRand(16*8);
+ pkt.append(_reconnectProof.AsByteBuffer()); // 16 bytes random
+ pkt << (uint64) 0x00 << (uint64) 0x00; // 16 bytes zeros
+ SendBuf((char const*)pkt.contents(), pkt.size());
+ return true;
+}
+
+/// Reconnect Proof command handler
+bool AuthSocket::_HandleReconnectProof()
+{
+ DEBUG_LOG("Entering _HandleReconnectProof");
+ ///- Read the packet
+ if (ibuf.GetLength() < sizeof(sAuthReconnectProof_C))
+ return false;
+ if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
+ return false;
+ sAuthReconnectProof_C lp;
+ ibuf.Read((char *)&lp, sizeof(sAuthReconnectProof_C));
+
+ BigNumber t1;
+ t1.SetBinary(lp.R1, 16);
+
+ Sha1Hash sha;
+ sha.Initialize();
+ sha.UpdateData(_login);
+ sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL);
+ sha.Finalize();
+
+ if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH))
+ {
+ ///- Sending response
+ ByteBuffer pkt;
+ pkt << (uint8) AUTH_RECONNECT_PROOF;
+ pkt << (uint8) 0x00;
+ pkt << (uint16) 0x00; // 2 bytes zeros
+ SendBuf((char const*)pkt.contents(), pkt.size());
+
+ ///- Set _authed to true!
+ _authed = true;
+
+ return true;
+ }
+ else
+ {
+ sLog.outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str());
+ SetCloseAndDelete();
+ return false;
+ }
+}
+
+/// %Realm List command handler
+bool AuthSocket::_HandleRealmList()
+{
+ DEBUG_LOG("Entering _HandleRealmList");
+ if (ibuf.GetLength() < 5)
+ return false;
+
+ ibuf.Remove(5);
+
+ ///- Get the user id (else close the connection)
+ // No SQL injection (escaped user name)
+
+ QueryResult *result = LoginDatabase.PQuery("SELECT id,sha_pass_hash FROM account WHERE username = '%s'",_safelogin.c_str());
+ if(!result)
+ {
+ sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str());
+ SetCloseAndDelete();
+ return false;
+ }
+
+ uint32 id = (*result)[0].GetUInt32();
+ std::string rI = (*result)[1].GetCppString();
+ delete result;
+
+ ///- Update realm list if need
+ m_realmList.UpdateIfNeed();
+
+ ///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm)
+ ByteBuffer pkt;
+ pkt << (uint32) 0;
+ pkt << (uint16) m_realmList.size();
+ RealmList::RealmMap::const_iterator i;
+ for( i = m_realmList.begin(); i != m_realmList.end(); i++ )
+ {
+ uint8 AmountOfCharacters;
+
+ // No SQL injection. id of realm is controlled by the database.
+ result = LoginDatabase.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id);
+ if( result )
+ {
+ Field *fields = result->Fetch();
+ AmountOfCharacters = fields[0].GetUInt8();
+ delete result;
+ }
+ else
+ AmountOfCharacters = 0;
+
+ uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
+
+ pkt << i->second.icon; // realm type
+ pkt << lock; // if 1, then realm locked
+ pkt << i->second.color; // if 2, then realm is offline
+ pkt << i->first;
+ pkt << i->second.address;
+ pkt << i->second.populationLevel;
+ pkt << AmountOfCharacters;
+ pkt << i->second.timezone; // realm category
+ pkt << (uint8) 0x2C; // unk, may be realm number/id?
+ }
+ pkt << (uint8) 0x10;
+ pkt << (uint8) 0x00;
+
+ ByteBuffer hdr;
+ hdr << (uint8) REALM_LIST;
+ hdr << (uint16)pkt.size();
+ hdr.append(pkt);
+
+ SendBuf((char const*)hdr.contents(), hdr.size());
+
+ // Set check field before possible relogin to realm
+ _SetVSFields(rI);
+ return true;
+}
+
+/// Resume patch transfer
+bool AuthSocket::_HandleXferResume()
+{
+ DEBUG_LOG("Entering _HandleXferResume");
+ ///- Check packet length and patch existence
+ if (ibuf.GetLength()<9 || !pPatch)
+ {
+ sLog.outError("Error while resuming patch transfer (wrong packet)");
+ return false;
+ }
+
+ ///- Launch a PatcherRunnable thread starting at given patch file offset
+ uint64 start;
+ ibuf.Remove(1);
+ ibuf.Read((char*)&start,sizeof(start));
+ fseek(pPatch,start,0);
+
+ ZThread::Thread u(new PatcherRunnable(this));
+ return true;
+}
+
+/// Cancel patch transfer
+bool AuthSocket::_HandleXferCancel()
+{
+ DEBUG_LOG("Entering _HandleXferCancel");
+
+ ///- Close and delete the socket
+ ibuf.Remove(1); //clear input buffer
+
+ //ZThread::Thread::sleep(15);
+ SetCloseAndDelete();
+
+ return true;
+}
+
+/// Accept patch transfer
+bool AuthSocket::_HandleXferAccept()
+{
+ DEBUG_LOG("Entering _HandleXferAccept");
+
+ ///- Check packet length and patch existence
+ if (!pPatch)
+ {
+ sLog.outError("Error while accepting patch transfer (wrong packet)");
+ return false;
+ }
+
+ ///- Launch a PatcherRunnable thread, starting at the begining of the patch file
+ ibuf.Remove(1); //clear input buffer
+ fseek(pPatch,0,0);
+
+ ZThread::Thread u(new PatcherRunnable(this));
+
+ return true;
+}
+
+/// Check if there is lag on the connection to the client
+bool AuthSocket::IsLag()
+{
+ return (TCP_BUFSIZE_READ-GetOutputLength()< 2*ChunkSize);
+}
+
+PatcherRunnable::PatcherRunnable(class AuthSocket * as)
+{
+ mySocket=as;
+}
+
+/// Send content of patch file to the client
+void PatcherRunnable::run()
+{
+ ZThread::Guard<ZThread::Mutex> g(mySocket->patcherLock);
+ XFER_DATA_STRUCT xfdata;
+ xfdata.opcode = XFER_DATA;
+
+ while(!feof(mySocket->pPatch) && mySocket->Ready())
+ {
+ ///- Wait until output buffer is reasonably empty
+ while(mySocket->Ready() && mySocket->IsLag())
+ {
+ ZThread::Thread::sleep(1);
+ }
+ ///- And send content of the patch file to the client
+ xfdata.data_size=fread(&xfdata.data,1,ChunkSize,mySocket->pPatch);
+ mySocket->SendBuf((const char*)&xfdata,xfdata.data_size +(sizeof(XFER_DATA_STRUCT)-ChunkSize));
+ }
+}
+
+/// Preload MD5 hashes of existing patch files on server
+#ifndef _WIN32
+#include <dirent.h>
+#include <errno.h>
+void Patcher::LoadPatchesInfo()
+{
+ DIR * dirp;
+ //int errno;
+ struct dirent * dp;
+ dirp = opendir("./patches/");
+ if(!dirp)
+ return;
+ while (dirp)
+ {
+ errno = 0;
+ if ((dp = readdir(dirp)) != NULL)
+ {
+ int l=strlen(dp->d_name);
+ if(l<8)continue;
+ if(!memcmp(&dp->d_name[l-4],".mpq",4))
+ LoadPatchMD5(dp->d_name);
+ }
+ else
+ {
+ if(errno != 0)
+ {
+ closedir(dirp);
+ return;
+ }
+ break;
+ }
+ }
+
+ if(dirp)
+ closedir(dirp);
+}
+
+#else
+void Patcher::LoadPatchesInfo()
+{
+ WIN32_FIND_DATA fil;
+ HANDLE hFil=FindFirstFile("./patches/*.mpq",&fil);
+ if(hFil==INVALID_HANDLE_VALUE)
+ return; //no patches were found
+
+ do
+ {
+ LoadPatchMD5(fil.cFileName);
+ }
+ while(FindNextFile(hFil,&fil));
+}
+#endif
+
+/// Calculate and store MD5 hash for a given patch file
+void Patcher::LoadPatchMD5(char * szFileName)
+{
+ ///- Try to open the patch file
+ std::string path = "./patches/";
+ path += szFileName;
+ FILE * pPatch=fopen(path.c_str(),"rb");
+ sLog.outDebug("Loading patch info from %s\n",path.c_str());
+ if(!pPatch)
+ {
+ sLog.outError("Error loading patch %s\n",path.c_str());
+ return;
+ }
+
+ ///- Calculate the MD5 hash
+ MD5_CTX ctx;
+ MD5_Init(&ctx);
+ uint8* buf = new uint8[512*1024];
+
+ while (!feof(pPatch))
+ {
+ size_t read = fread(buf, 1, 512*1024, pPatch);
+ MD5_Update(&ctx, buf, read);
+ }
+ delete [] buf;
+ fclose(pPatch);
+
+ ///- Store the result in the internal patch hash map
+ _patches[path] = new PATCH_INFO;
+ MD5_Final((uint8 *)&_patches[path]->md5 , &ctx);
+}
+
+/// Get cached MD5 hash for a given patch file
+bool Patcher::GetHash(char * pat,uint8 mymd5[16])
+{
+ for( Patches::iterator i = _patches.begin(); i != _patches.end(); i++ )
+ if(!stricmp(pat,i->first.c_str () ))
+ {
+ memcpy(mymd5,i->second->md5,16);
+ return true;
+ }
+
+ return false;
+}
+
+/// Launch the patch hashing mechanism on object creation
+Patcher::Patcher()
+{
+ LoadPatchesInfo();
+}
+
+/// Empty and delete the patch map on termination
+Patcher::~Patcher()
+{
+ for(Patches::iterator i = _patches.begin(); i != _patches.end(); i++ )
+ delete i->second;
+}
diff --git a/src/trinityrealm/Main.cpp b/src/trinityrealm/Main.cpp
new file mode 100644
index 00000000000..e74cd5144d3
--- /dev/null
+++ b/src/trinityrealm/Main.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/// \addtogroup realmd Realm Daemon
+/// @{
+/// \file
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "RealmList.h"
+
+#include "Config/ConfigEnv.h"
+#include "Log.h"
+#include "sockets/ListenSocket.h"
+#include "AuthSocket.h"
+#include "SystemConfig.h"
+#include "Util.h"
+
+// Format is YYYYMMDDRR where RR is the change in the conf file
+// for that day.
+#ifndef _REALMDCONFVERSION
+# define _REALMDCONFVERSION 2007062001
+#endif
+
+#ifndef _TRINITY_REALM_CONFIG
+# define _TRINITY_REALM_CONFIG "trinityrealm.conf"
+#endif //_TRINITY_REALM_CONFIG
+
+#ifdef WIN32
+#include "ServiceWin32.h"
+char serviceName[] = "realmd";
+char serviceLongName[] = "Trinity realm service";
+char serviceDescription[] = "Massive Network Game Object Server";
+/*
+ * -1 - not in service mode
+ * 0 - stopped
+ * 1 - running
+ * 2 - paused
+ */
+int m_ServiceStatus = -1;
+#endif
+
+bool StartDB(std::string &dbstring);
+void UnhookSignals();
+void HookSignals();
+
+bool stopEvent = false; ///< Setting it to true stops the server
+RealmList m_realmList; ///< Holds the list of realms for this server
+
+DatabaseType LoginDatabase; ///< Accessor to the realm server database
+
+/// Print out the usage string for this program on the console.
+void usage(const char *prog)
+{
+ sLog.outString("Usage: \n %s [<options>]\n"
+ " -c config_file use config_file as configuration file\n\r"
+ #ifdef WIN32
+ " Running as service functions:\n\r"
+ " --service run as service\n\r"
+ " -s install install service\n\r"
+ " -s uninstall uninstall service\n\r"
+ #endif
+ ,prog);
+}
+
+/// Launch the realm server
+extern int main(int argc, char **argv)
+{
+ ///- Command line parsing to get the configuration file name
+ char const* cfg_file = _TRINITY_REALM_CONFIG;
+ int c=1;
+ while( c < argc )
+ {
+ if( strcmp(argv[c],"-c") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -c option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ else
+ cfg_file = argv[c];
+ }
+
+ #ifdef WIN32
+ ////////////
+ //Services//
+ ////////////
+ if( strcmp(argv[c],"-s") == 0)
+ {
+ if( ++c >= argc )
+ {
+ sLog.outError("Runtime-Error: -s option requires an input argument");
+ usage(argv[0]);
+ return 1;
+ }
+ if( strcmp(argv[c],"install") == 0)
+ {
+ if (WinServiceInstall())
+ sLog.outString("Installing service");
+ return 1;
+ }
+ else if( strcmp(argv[c],"uninstall") == 0)
+ {
+ if(WinServiceUninstall())
+ sLog.outString("Uninstalling service");
+ return 1;
+ }
+ else
+ {
+ sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ if( strcmp(argv[c],"--service") == 0)
+ {
+ WinServiceRun();
+ }
+ ////
+ #endif
+ ++c;
+ }
+
+ if (!sConfig.SetSource(cfg_file))
+ {
+ sLog.outError("Could not find configuration file %s.", cfg_file);
+ return 1;
+ }
+ sLog.outString("Using configuration file %s.", cfg_file);
+
+ ///- Check the version of the configuration file
+ uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
+ if (confVersion < _REALMDCONFVERSION)
+ {
+ sLog.outError("*****************************************************************************");
+ sLog.outError(" WARNING: Your trinityrealm.conf version indicates your conf file is out of date!");
+ sLog.outError(" Please check for updates, as your current default values may cause");
+ sLog.outError(" strange behavior.");
+ sLog.outError("*****************************************************************************");
+ clock_t pause = 3000 + clock();
+
+ while (pause > clock()) {}
+ }
+
+ sLog.outString( "%s (realm-daemon)", _FULLVERSION );
+ sLog.outString( "<Ctrl-C> to stop.\n" );
+
+ /// realmd PID file creation
+ std::string pidfile = sConfig.GetStringDefault("PidFile", "");
+ if(!pidfile.empty())
+ {
+ uint32 pid = CreatePIDFile(pidfile);
+ if( !pid )
+ {
+ sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() );
+ return 1;
+ }
+
+ sLog.outString( "Daemon PID: %u\n", pid );
+ }
+
+ ///- Initialize the database connection
+ std::string dbstring;
+ if(!StartDB(dbstring))
+ return 1;
+
+ ///- Get the list of realms for the server
+ m_realmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20));
+ if (m_realmList.size() == 0)
+ {
+ sLog.outError("No valid realms specified.");
+ return 1;
+ }
+
+ ///- Launch the listening network socket
+ port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT );
+ std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
+
+ SocketHandler h;
+ ListenSocket<AuthSocket> authListenSocket(h);
+ if ( authListenSocket.Bind(bind_ip.c_str(),rmport))
+ {
+ sLog.outError( "Trinity realm can not bind to %s:%d",bind_ip.c_str(), rmport );
+ return 1;
+ }
+
+ h.Add(&authListenSocket);
+
+ ///- Catch termination signals
+ HookSignals();
+
+ ///- Handle affinity for multiple processors and process priority on Windows
+ #ifdef WIN32
+ {
+ HANDLE hProcess = GetCurrentProcess();
+
+ uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
+ if(Aff > 0)
+ {
+ ULONG_PTR appAff;
+ ULONG_PTR sysAff;
+
+ if(GetProcessAffinityMask(hProcess,&appAff,&sysAff))
+ {
+ ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
+
+ if(!curAff )
+ {
+ sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. Accessible processors bitmask (hex): %x",Aff,appAff);
+ }
+ else
+ {
+ if(SetProcessAffinityMask(hProcess,curAff))
+ sLog.outString("Using processors (bitmask, hex): %x", curAff);
+ else
+ sLog.outError("Can't set used processors (hex): %x", curAff);
+ }
+ }
+ sLog.outString();
+ }
+
+ bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
+
+ if(Prio)
+ {
+ if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
+ sLog.outString("TrinityRealm process priority class set to HIGH");
+ else
+ sLog.outError("ERROR: Can't set realmd process priority class.");
+ sLog.outString();
+ }
+ }
+ #endif
+
+ // maximum counter for next ping
+ uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000));
+ uint32 loopCounter = 0;
+
+ ///- Wait for termination signal
+ while (!stopEvent)
+ {
+
+ h.Select(0, 100000);
+
+ if( (++loopCounter) == numLoops )
+ {
+ loopCounter = 0;
+ sLog.outDetail("Ping MySQL to keep connection alive");
+ delete LoginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1");
+ }
+#ifdef WIN32
+ if (m_ServiceStatus == 0) stopEvent = true;
+ while (m_ServiceStatus == 2) Sleep(1000);
+#endif
+ }
+
+ ///- Wait for the delay thread to exit
+ LoginDatabase.HaltDelayThread();
+
+ ///- Remove signal handling before leaving
+ UnhookSignals();
+
+ sLog.outString( "Halting process..." );
+ return 0;
+}
+
+/// Handle termination signals
+/** Put the global variable stopEvent to 'true' if a termination signal is caught **/
+void OnSignal(int s)
+{
+ switch (s)
+ {
+ case SIGINT:
+ case SIGTERM:
+ stopEvent = true;
+ break;
+ #ifdef _WIN32
+ case SIGBREAK:
+ stopEvent = true;
+ break;
+ #endif
+ }
+
+ signal(s, OnSignal);
+}
+
+/// Initialize connection to the database
+bool StartDB(std::string &dbstring)
+{
+ if(!sConfig.GetString("LoginDatabaseInfo", &dbstring))
+ {
+ sLog.outError("Database not specified");
+ return false;
+ }
+
+ sLog.outString("Database: %s", dbstring.c_str() );
+ if(!LoginDatabase.Initialize(dbstring.c_str()))
+ {
+ sLog.outError("Cannot connect to database");
+ return false;
+ }
+
+ return true;
+}
+
+/// Define hook 'OnSignal' for all termination signals
+void HookSignals()
+{
+ signal(SIGINT, OnSignal);
+ signal(SIGTERM, OnSignal);
+ #ifdef _WIN32
+ signal(SIGBREAK, OnSignal);
+ #endif
+}
+
+/// Unhook the signals before leaving
+void UnhookSignals()
+{
+ signal(SIGINT, 0);
+ signal(SIGTERM, 0);
+ #ifdef _WIN32
+ signal(SIGBREAK, 0);
+ #endif
+}
+
+/// @}
diff --git a/src/trinityrealm/RealmList.cpp b/src/trinityrealm/RealmList.cpp
new file mode 100644
index 00000000000..32c0cbc12c1
--- /dev/null
+++ b/src/trinityrealm/RealmList.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \file
+ \ingroup realmd
+*/
+
+#include "Common.h"
+#include "RealmList.h"
+#include "Policies/SingletonImp.h"
+#include "Database/DatabaseEnv.h"
+
+INSTANTIATE_SINGLETON_1( RealmList );
+
+extern DatabaseType LoginDatabase;
+
+RealmList::RealmList( ) : m_UpdateInterval(0), m_NextUpdateTime(time(NULL))
+{
+}
+
+/// Load the realm list from the database
+void RealmList::Initialize(uint32 updateInterval)
+{
+ m_UpdateInterval = updateInterval;
+
+ ///- Get the content of the realmlist table in the database
+ UpdateRealms(true);
+}
+
+void RealmList::UpdateRealm( uint32 ID, const std::string& name, const std::string& address, uint32 port, uint8 icon, uint8 color, uint8 timezone, AccountTypes allowedSecurityLevel, float popu)
+{
+ ///- Create new if not exist or update existed
+ Realm& realm = m_realms[name];
+
+ realm.m_ID = ID;
+ realm.name = name;
+ realm.icon = icon;
+ realm.color = color;
+ realm.timezone = timezone;
+ realm.allowedSecurityLevel = allowedSecurityLevel;
+ realm.populationLevel = popu;
+
+ ///- Append port to IP address.
+ std::ostringstream ss;
+ ss << address << ":" << port;
+ realm.address = ss.str();
+}
+
+void RealmList::UpdateIfNeed()
+{
+ // maybe disabled or updated recently
+ if(!m_UpdateInterval || m_NextUpdateTime > time(NULL))
+ return;
+
+ m_NextUpdateTime = time(NULL) + m_UpdateInterval;
+
+ // Clears Realm list
+ m_realms.clear();
+
+ // Get the content of the realmlist table in the database
+ UpdateRealms(false);
+}
+
+void RealmList::UpdateRealms(bool init)
+{
+ sLog.outDetail("Updating Realm List...");
+
+ QueryResult *result = LoginDatabase.Query( "SELECT id, name, address, port, icon, color, timezone, allowedSecurityLevel, population FROM realmlist WHERE color <> 3 ORDER BY name" );
+
+ ///- Circle through results and add them to the realm map
+ if(result)
+ {
+ do
+ {
+ Field *fields = result->Fetch();
+
+ uint8 allowedSecurityLevel = fields[7].GetUInt8();
+
+ UpdateRealm(fields[0].GetUInt32(), fields[1].GetCppString(),fields[2].GetCppString(),fields[3].GetUInt32(),fields[4].GetUInt8(), fields[5].GetUInt8(), fields[6].GetUInt8(), (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), fields[8].GetFloat() );
+ if(init)
+ sLog.outString("Added realm \"%s\".", fields[1].GetString());
+ } while( result->NextRow() );
+ delete result;
+ }
+}