/*
* Ascent MMORPG Server
* Copyright (C) 2005-2007 Ascent Team
*
* 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 3 of the License, or
* 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, see .
*
*/
#include "StdAfx.h"
initialiseSingleton( ObjectMgr );
#ifdef WIN32
#define ToLower(yourstring) transform (yourstring.begin(),yourstring.end(), yourstring.begin(), tolower);
#else
#define ToLower(str) for(unsigned int i=0;isecond;
}
mItemSets.clear();
sLog.outString(" Deleting CreateInfo...");
for( PlayerCreateInfoMap::iterator i = mPlayerCreateInfo.begin( ); i != mPlayerCreateInfo.end( ); ++ i ) {
delete i->second;
}
mPlayerCreateInfo.clear( );
sLog.outString(" Deleting Guilds...");
for ( GuildMap::iterator i = mGuild.begin(); i != mGuild.end(); ++i ) {
delete i->second;
}
sLog.outString(" Deleting Vendors...");
for( VendorMap::iterator i = mVendors.begin( ); i != mVendors.end( ); ++ i )
{
delete i->second;
}
sLog.outString(" Deleting AI Threat Spells...");
for( ThreadToSpellList::iterator i = threatToSpells.begin( ); i != threatToSpells.end( ); ++ i )
{
ThreatToSpellId *gc=(*i);
delete gc;
}
sLog.outString(" Deleting Spell Override Map...");
for(OverrideIdMap::iterator i = mOverrideIdMap.begin(); i != mOverrideIdMap.end(); ++i)
{
delete i->second;
}
for( TrainerMap::iterator i = mTrainers.begin( ); i != mTrainers.end( ); ++ i) {
Trainer * t = i->second;
if(t->TrainMsg)
delete [] t->TrainMsg;
if(t->NoTrainMsg)
delete [] t->NoTrainMsg;
if(t->SpellList)
delete [] t->SpellList;
if(t->TalkMessage)
delete [] t->TalkMessage;
delete t;
}
for(TrainerSpellMap::iterator i = mNormalSpells.begin(); i != mNormalSpells.end(); ++i)
{
vector::iterator itr = i->second.begin();
for(; itr != i->second.end(); ++itr)
{
delete (*itr);
}
i->second.clear();
}
for(TrainerSpellMap::iterator i = mPetSpells.begin(); i != mPetSpells.end(); ++i)
{
vector::iterator itr = i->second.begin();
for(; itr != i->second.end(); ++itr)
{
delete (*itr);
}
i->second.clear();
}
for( LevelInfoMap::iterator i = mLevelInfo.begin(); i != mLevelInfo.end(); ++i)
{
LevelMap * l = i->second;
for(LevelMap::iterator i2 = l->begin(); i2 != l->end(); ++i2)
{
delete i2->second;
}
l->clear();
delete l;
}
/*if(m_transporters)
{
for(uint32 i = 1; i <= this->TransportersCount; ++i)
{
if(m_transporters[i])
{
delete m_transporters[i];
m_transporters[i] = 0;
}
}
delete [] m_transporters;
}*/
/*BURSTORAGEREWRITEFIX*/
/*sLog.outString("Deleting Prototypes/Waypoints/AISpells...");
for(HM_NAMESPACE::hash_map::iterator itr = m_creatureproto.begin(); itr != m_creatureproto.end(); ++itr)
{
CreatureProto * p = itr->second;
for(list::iterator i = p->spells.begin(); i != p->spells.end(); ++i)
delete (*i);
delete p;
}*/
/*for(HM_NAMESPACE::hash_map::iterator i = mTransports.begin(); i != mTransports.end(); ++i)
{
delete i->second;
}*/
for(HM_NAMESPACE::hash_map::iterator i = m_waypoints.begin(); i != m_waypoints.end(); ++i)
{
for(WayPointMap::iterator i2 = i->second->begin(); i2 != i->second->end(); ++i2)
delete (*i2);
delete i->second;
}
for(HM_NAMESPACE::hash_map::iterator itr = m_playersinfo.begin(); itr != m_playersinfo.end(); ++itr)
delete itr->second;
sLog.outString("Deleting npc_monstersay...");
for(uint32 i = 0 ; i < NUM_MONSTER_SAY_EVENTS ; ++i)
{
NpcMonsterSay * p;
for(MonsterSayMap::iterator itr = mMonsterSays[i].begin(); itr != mMonsterSays[i].end(); ++itr)
{
p = itr->second;
for(uint32 j = 0; j < p->TextCount; ++j)
free((char*)p->Texts[j]);
delete [] p->Texts;
free((char*)p->MonsterName);
delete p;
}
mMonsterSays[i].clear();
}
sLog.outString("Deleting Charters...");
for(HM_NAMESPACE::hash_map::iterator itr = m_charters.begin(); itr != m_charters.end(); ++itr)
{
delete itr->second;
}
sLog.outString("Deleting reputation tables...");
for(ReputationModMap::iterator itr = this->m_reputation_creature.begin(); itr != m_reputation_creature.end(); ++itr)
{
ReputationModifier * mod = itr->second;
mod->mods.clear();
delete mod;
}
for(ReputationModMap::iterator itr = this->m_reputation_faction.begin(); itr != m_reputation_faction.end(); ++itr)
{
ReputationModifier * mod = itr->second;
mod->mods.clear();
delete mod;
}
for(HM_NAMESPACE::hash_map::iterator itr = this->m_reputation_instance.begin(); itr != this->m_reputation_instance.end(); ++itr)
{
InstanceReputationModifier * mod = itr->second;
mod->mods.clear();
delete mod;
}
}
//
// Groups
//
Group * ObjectMgr::GetGroupByLeader(Player* pPlayer)
{
GroupSet::const_iterator itr;
for (itr = mGroupSet.begin(); itr != mGroupSet.end(); itr++)
{
if ((*itr)->GetLeader() == pPlayer)
{
return *itr;
}
}
return NULL;
}
Group * ObjectMgr::GetGroupById(uint32 id)
{
GroupSet::const_iterator itr;
for (itr = mGroupSet.begin(); itr != mGroupSet.end(); itr++)
{
if ((*itr)->GetID() == id)
{
return *itr;
}
}
return NULL;
}
//
// Player names
//
void ObjectMgr::DeletePlayerInfo( uint32 guid )
{
PlayerInfo * pl;
HM_NAMESPACE::hash_map::iterator i;
playernamelock.AcquireWriteLock();
i=m_playersinfo.find(guid);
if(i!=m_playersinfo.end())
{
pl=i->second;
if(pl->m_Group)
pl->m_Group->RemovePlayer(pl,NULL,true);
delete i->second;
m_playersinfo.erase(i);
}
playernamelock.ReleaseWriteLock();
}
PlayerInfo *ObjectMgr::GetPlayerInfo( uint32 guid )
{
HM_NAMESPACE::hash_map::iterator i;
PlayerInfo * rv;
playernamelock.AcquireReadLock();
i=m_playersinfo.find(guid);
if(i!=m_playersinfo.end())
rv = i->second;
else
rv = NULL;
playernamelock.ReleaseReadLock();
return rv;
}
void ObjectMgr::AddPlayerInfo(PlayerInfo *pn)
{
playernamelock.AcquireWriteLock();
m_playersinfo[pn->guid] = pn ;
playernamelock.ReleaseWriteLock();
}
void ObjectMgr::LoadSpellSkills()
{
uint32 i;
// int total = sSkillStore.GetNumRows();
for(i = 0; i < sSkillStore.GetNumRows(); i++)
{
skilllinespell *sp = sSkillStore.LookupEntry(i);
if (sp)
{
mSpellSkills[sp->spell] = sp;
}
}
Log.Notice("ObjectMgr", "%u spell skills loaded.", mSpellSkills.size());
}
skilllinespell* ObjectMgr::GetSpellSkill(uint32 id)
{
return mSpellSkills[id];
}
void ObjectMgr::LoadPlayersInfo()
{
PlayerInfo * pn;
QueryResult *result = CharacterDatabase.Query("SELECT guid,name,race,class,level,gender,zoneId,timestamp,publicNote,officerNote,guildRank,acct FROM characters");
if(result)
{
do
{
Field *fields = result->Fetch();
pn=new PlayerInfo;
pn->guid = fields[0].GetUInt64();
pn->name = fields[1].GetString();
pn->race = fields[2].GetUInt8();
pn->cl = fields[3].GetUInt8();
pn->lastLevel = fields[4].GetUInt32();
pn->gender = fields[5].GetUInt8();
pn->lastZone=fields[6].GetUInt32();
pn->lastOnline=fields[7].GetUInt32();
pn->publicNote=fields[8].GetString();
pn->officerNote= fields[9].GetString();
pn->Rank=fields[10].GetUInt32();
pn->acct = fields[11].GetUInt32();
pn->m_Group=0;
pn->subGroup=0;
if(pn->race==RACE_HUMAN||pn->race==RACE_DWARF||pn->race==RACE_GNOME||pn->race==RACE_NIGHTELF||pn->race==RACE_DRAENEI)
pn->team = 0;
else
pn->team = 1;
//this is startup -> no need in lock -> don't use addplayerinfo
m_playersinfo[(uint32)pn->guid]=pn;
} while( result->NextRow() );
delete result;
}
Log.Notice("ObjectMgr", "%u players loaded.", m_playersinfo.size());
LoadGuilds();
}
PlayerInfo* ObjectMgr::GetPlayerInfoByName(std::string &name)
{
HM_NAMESPACE::hash_map::const_iterator i;
PlayerInfo * rv = 0;
playernamelock.AcquireReadLock();
for(i=m_playersinfo.begin();i!=m_playersinfo.end();i++)
if(!stricmp(i->second->name.c_str(),name.c_str()))
{
rv = i->second;
break;
}
playernamelock.ReleaseReadLock();
return rv;
}
void ObjectMgr::LoadPlayerCreateInfo()
{
QueryResult *result = WorldDatabase.Query( "SELECT * FROM playercreateinfo" );
if( !result )
{
Log.Error("MySQL","Query failed: SELECT * FROM playercreateinfo");
return;
}
PlayerCreateInfo *pPlayerCreateInfo;
do
{
Field *fields = result->Fetch();
pPlayerCreateInfo = new PlayerCreateInfo;
pPlayerCreateInfo->index = fields[0].GetUInt8();
pPlayerCreateInfo->race = fields[1].GetUInt8();
pPlayerCreateInfo->factiontemplate = fields[2].GetUInt32();
pPlayerCreateInfo->class_ = fields[3].GetUInt8();
pPlayerCreateInfo->mapId = fields[4].GetUInt32();
pPlayerCreateInfo->zoneId = fields[5].GetUInt32();
pPlayerCreateInfo->positionX = fields[6].GetFloat();
pPlayerCreateInfo->positionY = fields[7].GetFloat();
pPlayerCreateInfo->positionZ = fields[8].GetFloat();
pPlayerCreateInfo->displayId = fields[9].GetUInt16();
pPlayerCreateInfo->strength = fields[10].GetUInt8();
pPlayerCreateInfo->ability = fields[11].GetUInt8();
pPlayerCreateInfo->stamina = fields[12].GetUInt8();
pPlayerCreateInfo->intellect = fields[13].GetUInt8();
pPlayerCreateInfo->spirit = fields[14].GetUInt8();
pPlayerCreateInfo->health = fields[15].GetUInt32();
pPlayerCreateInfo->mana = fields[16].GetUInt32();
pPlayerCreateInfo->rage = fields[17].GetUInt32();
pPlayerCreateInfo->focus = fields[18].GetUInt32();
pPlayerCreateInfo->energy = fields[19].GetUInt32();
pPlayerCreateInfo->attackpower = fields[20].GetUInt32();
pPlayerCreateInfo->mindmg = fields[21].GetFloat();
pPlayerCreateInfo->maxdmg = fields[22].GetFloat();
QueryResult *sk_sql = WorldDatabase.Query(
"SELECT * FROM playercreateinfo_skills WHERE indexid=%u",pPlayerCreateInfo->index);
if(sk_sql)
{
do
{
Field *fields = sk_sql->Fetch();
CreateInfo_SkillStruct tsk;
tsk.skillid = fields[1].GetUInt32();
tsk.currentval = fields[2].GetUInt32();
tsk.maxval = fields[3].GetUInt32();
pPlayerCreateInfo->skills.push_back(tsk);
} while(sk_sql->NextRow());
delete sk_sql;
}
QueryResult *sp_sql = WorldDatabase.Query(
"SELECT * FROM playercreateinfo_spells WHERE indexid=%u",pPlayerCreateInfo->index);
if(sp_sql)
{
do
{
pPlayerCreateInfo->spell_list.push_back(sp_sql->Fetch()[1].GetUInt16());
} while(sp_sql->NextRow());
delete sp_sql;
}
QueryResult *items_sql = WorldDatabase.Query(
"SELECT * FROM playercreateinfo_items WHERE indexid=%u",pPlayerCreateInfo->index);
if(items_sql)
{
do
{
Field *fields = items_sql->Fetch();
CreateInfo_ItemStruct itm;
itm.protoid = fields[1].GetUInt32();
itm.slot = fields[2].GetUInt8();
itm.amount = fields[3].GetUInt32();
pPlayerCreateInfo->items.push_back(itm);
} while(items_sql->NextRow());
delete items_sql;
}
QueryResult *bars_sql = WorldDatabase.Query(
"SELECT * FROM playercreateinfo_bars WHERE class=%u",pPlayerCreateInfo->class_ );
if(bars_sql)
{
do
{
Field *fields = bars_sql->Fetch();
CreateInfo_ActionBarStruct bar;
bar.button = fields[2].GetUInt32();
bar.action = fields[3].GetUInt32();
bar.type = fields[4].GetUInt32();
bar.misc = fields[5].GetUInt32();
pPlayerCreateInfo->actionbars.push_back(bar);
} while(bars_sql->NextRow());
delete bars_sql;
}
mPlayerCreateInfo[pPlayerCreateInfo->index] = pPlayerCreateInfo;
} while( result->NextRow() );
delete result;
Log.Notice("ObjectMgr", "%u player create infos loaded.", mPlayerCreateInfo.size());
GenerateLevelUpInfo();
}
// DK:LoadGuilds()
void ObjectMgr::LoadGuilds()
{
QueryResult *result = CharacterDatabase.Query( "SELECT * FROM guilds" );
QueryResult *result2;
QueryResult *result3;
if(!result)
{
return;
}
Guild *pGuild;
struct RankInfo rankList;
do
{
Field *fields = result->Fetch();
pGuild = new Guild;
pGuild->SetGuildId( fields[0].GetUInt32() );
pGuild->SetGuildName( fields[1].GetString() );
pGuild->SetGuildLeaderGuid(fields[2].GetUInt64() );
pGuild->SetGuildEmblemStyle( fields[3].GetUInt32() );
pGuild->SetGuildEmblemColor(fields[4].GetUInt32() );
pGuild->SetGuildBorderStyle( fields[5].GetUInt32() );
pGuild->SetGuildBorderColor( fields[6].GetUInt32() );
pGuild->SetGuildBackgroundColor( fields[7].GetUInt32() );
pGuild->SetGuildInfo( fields[8].GetString() );
pGuild->SetGuildMotd( fields[9].GetString() );
result2 = CharacterDatabase.Query( "SELECT guid FROM characters WHERE guildId=%u",pGuild->GetGuildId());
if(result2)
{
do
{
PlayerInfo *pi=objmgr.GetPlayerInfo(result2->Fetch()->GetUInt64());
if(pi)
pGuild->AddGuildMember( pi );
}while( result2->NextRow() );
delete result2;
}
result3 = CharacterDatabase.Query("SELECT * FROM guild_ranks WHERE guildId=%u ORDER BY rankId", pGuild->GetGuildId());
if(result3)
{
do
{
Field *fields3 = result3->Fetch();
rankList.name = fields3[2].GetString();
rankList.rights = fields3[3].GetUInt32();
pGuild->CreateRank(rankList.name, rankList.rights );
}while( result3->NextRow() );
delete result3;
}
pGuild->LoadGuildCreationDate();
AddGuild(pGuild);
}while( result->NextRow() );
delete result;
Log.Notice("ObjectMgr", "%u guilds loaded.", mGuild.size());
}
Corpse* ObjectMgr::LoadCorpse(uint32 guid)
{
Corpse *pCorpse;
QueryResult *result = CharacterDatabase.Query("SELECT * FROM Corpses WHERE guid =%u ", guid );
if( !result )
return NULL;
do
{
Field *fields = result->Fetch();
pCorpse = new Corpse(HIGHGUID_CORPSE,fields[0].GetUInt32());
pCorpse->SetPosition(fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
pCorpse->SetZoneId(fields[5].GetUInt32());
pCorpse->SetMapId(fields[6].GetUInt32());
pCorpse->LoadValues( fields[7].GetString());
if(pCorpse->GetUInt32Value(CORPSE_FIELD_DISPLAY_ID) == 0)
{
delete pCorpse;
continue;
}
pCorpse->SetLoadedFromDB(true);
pCorpse->SetInstanceID(fields[8].GetUInt32());
pCorpse->AddToWorld();
} while( result->NextRow() );
delete result;
return pCorpse;
}
//------------------------------------------------------
// Live corpse retreival.
// comments: I use the same tricky method to start from the last corpse instead of the first
//------------------------------------------------------
Corpse *ObjectMgr::GetCorpseByOwner(uint32 ownerguid)
{
CorpseMap::const_iterator itr;
Corpse *rv = NULL;
_corpseslock.Acquire();
for (itr = m_corpses.begin();itr != m_corpses.end(); ++itr)
{
if(itr->second->GetUInt32Value(CORPSE_FIELD_OWNER) == ownerguid)
{
rv = itr->second;
break;
}
}
_corpseslock.Release();
return rv;
}
void ObjectMgr::DelinkPlayerCorpses(Player *pOwner)
{
//dupe protection agaisnt crashs
Corpse * c;
c=this->GetCorpseByOwner(pOwner->GetGUIDLow());
if(!c)return;
sEventMgr.AddEvent(c, &Corpse::Delink, EVENT_CORPSE_SPAWN_BONES, 1, 1, 0);
CorpseAddEventDespawn(c);
}
void ObjectMgr::LoadGMTickets()
{
QueryResult *result = CharacterDatabase.Query( "SELECT * FROM gm_tickets" );
GM_Ticket *ticket;
if(result == 0)
return;
do
{
Field *fields = result->Fetch();
ticket = new GM_Ticket;
ticket->guid = fields[0].GetUInt32();
ticket->name = fields[1].GetString();
ticket->level = fields[2].GetUInt32();
ticket->type = fields[3].GetUInt32();
ticket->posX = fields[4].GetFloat();
ticket->posY = fields[5].GetFloat();
ticket->posZ = fields[6].GetFloat();
ticket->message = fields[7].GetString();
ticket->timestamp = fields[8].GetUInt32();
AddGMTicket(ticket,true);
} while( result->NextRow() );
Log.Notice("ObjectMgr", "%u GM Tickets loaded.", result->GetRowCount());
delete result;
}
void ObjectMgr::SaveGMTicket(uint64 guid)
{
GM_Ticket* ticket = GetGMTicket(guid);
if(!ticket)
{
return;
}
std::stringstream ss1;
std::stringstream ss2;
ss1 << "DELETE FROM gm_tickets WHERE guid = " << guid << ";";
CharacterDatabase.Execute(ss1.str( ).c_str( ));
ss2 << "INSERT INTO gm_tickets (guid, name, level, type, posX, posY, posZ, message, timestamp) VALUES(";
ss2 << ticket->guid << ", '";
ss2 << CharacterDatabase.EscapeString(ticket->name) << "', ";
ss2 << ticket->level << ", ";
ss2 << ticket->type << ", ";
ss2 << ticket->posX << ", ";
ss2 << ticket->posY << ", ";
ss2 << ticket->posZ << ", '";
ss2 << CharacterDatabase.EscapeString(ticket->message) << "', ";
ss2 << ticket->timestamp << ");";
CharacterDatabase.Execute(ss2.str( ).c_str( ));
}
void ObjectMgr::SetHighestGuids()
{
QueryResult *result;
result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
if( result )
{
m_hiPlayerGuid = result->Fetch()[0].GetUInt32();
delete result;
}
result = CharacterDatabase.Query("SELECT MAX(guid) FROM playeritems");
if( result )
{
m_hiItemGuid = (uint32)result->Fetch()[0].GetUInt32();
delete result;
}
result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpses" );
if( result )
{
m_hiCorpseGuid = result->Fetch()[0].GetUInt32();
delete result;
}
result = WorldDatabase.Query("SELECT MAX(id) FROM creature_spawns");
if(result)
{
m_hiCreatureSpawnId = result->Fetch()[0].GetUInt32();
delete result;
}
result = WorldDatabase.Query("SELECT MAX(id) FROM gameobject_spawns");
if(result)
{
m_hiGameObjectSpawnId = result->Fetch()[0].GetUInt32();
delete result;
}
result = CharacterDatabase.Query("SELECT MAX(group_id) FROM groups");
if(result)
{
m_hiGroupId = result->Fetch()[0].GetUInt32();
delete result;
}
result = CharacterDatabase.Query("SELECT MAX(charterId) FROM charters");
if(result)
{
m_hiCharterId = result->Fetch()[0].GetUInt32();
delete result;
}
Log.Notice("ObjectMgr", "HighGuid(CORPSE) = %u", m_hiCorpseGuid);
Log.Notice("ObjectMgr", "HighGuid(PLAYER) = %u", m_hiPlayerGuid);
Log.Notice("ObjectMgr", "HighGuid(GAMEOBJ) = %u", m_hiGameObjectSpawnId);
Log.Notice("ObjectMgr", "HighGuid(UNIT) = %u", m_hiCreatureSpawnId);
Log.Notice("ObjectMgr", "HighGuid(ITEM) = %u", m_hiItemGuid);
Log.Notice("ObjectMgr", "HighGuid(CONTAINER) = %u", m_hiContainerGuid);
Log.Notice("ObjectMgr", "HighGuid(GROUP) = %u", m_hiGroupId);
Log.Notice("ObjectMgr", "HighGuid(CHARTER) = %u", m_hiCharterId);
}
uint32 ObjectMgr::GenerateMailID()
{
return m_mailid++;
}
uint32 ObjectMgr::GenerateLowGuid(uint32 guidhigh)
{
ASSERT(guidhigh == HIGHGUID_ITEM || guidhigh == HIGHGUID_CONTAINER);
uint32 ret;
if(guidhigh == HIGHGUID_ITEM)
{
m_guidGenMutex.Acquire();
ret = ++m_hiItemGuid;
m_guidGenMutex.Release();
}else
{
m_guidGenMutex.Acquire();
ret = ++m_hiContainerGuid;
m_guidGenMutex.Release();
}
return ret;
}
void ObjectMgr::ProcessGameobjectQuests()
{
/*if(!mGameObjectNames.size())
return;
int total = mGameObjectNames.size();
std::set tmp;
for(HM_NAMESPACE::hash_map::iterator itr = sQuestMgr.Begin(); itr != sQuestMgr.End(); ++itr)
{
Quest *qst = itr->second;
if(qst->count_required_item > 0 ||
qst->required_mobtype[0] == QUEST_MOB_TYPE_GAMEOBJECT ||
qst->required_mobtype[1] == QUEST_MOB_TYPE_GAMEOBJECT ||
qst->required_mobtype[2] == QUEST_MOB_TYPE_GAMEOBJECT ||
qst->required_mobtype[3] == QUEST_MOB_TYPE_GAMEOBJECT )
{
tmp.insert(qst);
}
}
std::vector gos;
gos.reserve(5000);
for(GameObjectNameMap::iterator it0 = mGameObjectNames.begin(); it0 != mGameObjectNames.end(); ++it0)
{
GameObjectInfo *gon = it0->second;
gos.push_back(it0->second);
}
int c = 0;
total = gos.size();
for(std::vector::iterator it0 = gos.begin(); it0 != gos.end(); ++it0)
{
GameObjectInfo *gon = (*it0);
map >* golootlist = &(LootMgr::getSingleton().quest_loot_go);
map >::iterator it2 = golootlist->find(gon->ID);
//// QUEST PARSING
for(std::set::iterator itr = tmp.begin(); itr != tmp.end(); ++itr)
{
Quest *qst = *itr;
int max = qst->count_required_mob;
if(qst->count_required_item > max)
max = qst->count_required_item;
if(max > 0)
{
for(int i = 0; i < max; ++i)
{
if(qst->required_mob[i] > 0)
{
if(qst->required_mob[i] == gon->ID &&
qst->required_mobtype[i] == QUEST_MOB_TYPE_GAMEOBJECT)
{
gon->goMap.insert( GameObjectGOMap::value_type( qst, qst->required_mobcount[i] ) );
sDatabase.WaitExecute("INSERT INTO gameobject_quest_pickup_binding VALUES(%u, %u, %u)",
gon->ID, qst->id, qst->required_mobcount[i]);
}
}
if(qst->required_itemcount[i] > 0 && it2 != golootlist->end())
{
// check our loot template for this item
for(std::set::iterator it4 = it2->second.begin(); it4 != it2->second.end(); ++it4)
{
if((*it4) == qst->required_item[i])
{
//GOQuestItem it;
//it.itemid = qst->required_item[i];
//it.requiredcount = qst->required_itemcount[i];
//gon->itemMap.insert( GameObjectItemMap::value_type( qst, it ) );
//gon->itemMap[qst].insert(it);
gon->itemMap[qst].insert( std::map::value_type( qst->required_item[i], qst->required_itemcount[i]) );
sDatabase.WaitExecute("INSERT INTO gameobject_quest_item_binding VALUES(%u, %u, %u, %u)",
gon->ID, qst->id, qst->required_item[i], qst->required_itemcount[i]);
}
}
}
}
}
}
c++;
if(!(c % 150))
SetProgressBar(c, total, "Binding");
}
ClearProgressBar();*/
QueryResult * result = WorldDatabase.Query("SELECT * FROM gameobject_quest_item_binding");
QueryResult * result2 = WorldDatabase.Query("SELECT * FROM gameobject_quest_pickup_binding");
GameObjectInfo * gon;
Quest * qst;
if(result)
{
do
{
Field * fields = result->Fetch();
gon = GameObjectNameStorage.LookupEntry(fields[0].GetUInt32());
qst = QuestStorage.LookupEntry(fields[1].GetUInt32());
if(gon && qst)
gon->itemMap[qst].insert( make_pair( fields[2].GetUInt32(), fields[3].GetUInt32() ) );
} while(result->NextRow());
delete result;
}
if(result2)
{
do
{
Field * fields = result2->Fetch();
gon = GameObjectNameStorage.LookupEntry(fields[0].GetUInt32());
qst = QuestStorage.LookupEntry(fields[1].GetUInt32());
if(gon && qst)
gon->goMap.insert( make_pair( qst, fields[2].GetUInt32() ) );
} while(result2->NextRow());
delete result2;
}
result = WorldDatabase.Query("SELECT * FROM npc_gossip_textid");
if(result)
{
uint32 entry, text;
do
{
entry = result->Fetch()[0].GetUInt32();
text = result->Fetch()[1].GetUInt32();
mNpcToGossipText[entry] = text;
} while(result->NextRow());
delete result;
}
Log.Notice("ObjectMgr", "%u NPC Gossip TextIds loaded.", mNpcToGossipText.size());
}
Player* ObjectMgr::GetPlayer(const char* name, bool caseSensitive)
{
Player * rv = NULL;
PlayerStorageMap::const_iterator itr;
_playerslock.AcquireReadLock();
if(!caseSensitive)
{
std::string strName = name;
std::transform(strName.begin(),strName.end(),strName.begin(),towlower);
for (itr = _players.begin(); itr != _players.end(); ++itr)
{
if(!stricmp(itr->second->GetNameString()->c_str(), strName.c_str()))
{
rv = itr->second;
break;
}
}
}
else
{
for (itr = _players.begin(); itr != _players.end(); ++itr)
{
if(!strcmp(itr->second->GetName(), name))
{
rv = itr->second;
break;
}
}
}
_playerslock.ReleaseReadLock();
return rv;
}
Player* ObjectMgr::GetPlayer(uint32 guid)
{
Player * rv;
_playerslock.AcquireReadLock();
PlayerStorageMap::const_iterator itr = _players.find(guid);
rv = (itr != _players.end()) ? itr->second : 0;
_playerslock.ReleaseReadLock();
return rv;
}
PlayerCreateInfo* ObjectMgr::GetPlayerCreateInfo(uint8 race, uint8 class_) const
{
PlayerCreateInfoMap::const_iterator itr;
for (itr = mPlayerCreateInfo.begin(); itr != mPlayerCreateInfo.end(); itr++)
{
if( (itr->second->race == race) && (itr->second->class_ == class_) )
return itr->second;
}
return NULL;
}
void ObjectMgr::AddGuild(Guild *pGuild)
{
ASSERT( pGuild );
mGuild[pGuild->GetGuildId()] = pGuild;
}
uint32 ObjectMgr::GetTotalGuildCount()
{
return mGuild.size();
}
bool ObjectMgr::RemoveGuild(uint32 guildId)
{
GuildMap::iterator i = mGuild.find(guildId);
if (i == mGuild.end())
{
return false;
}
i->second->RemoveFromDb();
mGuild.erase(i);
return true;
}
Guild* ObjectMgr::GetGuild(uint32 guildId)
{
GuildMap::const_iterator itr = mGuild.find(guildId);
if(itr == mGuild.end())
return NULL;
return itr->second;
}
Guild* ObjectMgr::GetGuildByLeaderGuid(uint64 leaderGuid)
{
GuildMap::const_iterator itr;
for (itr = mGuild.begin();itr != mGuild.end(); itr++)
{
if( itr->second->GetGuildLeaderGuid() == leaderGuid )
return itr->second;
}
return NULL;
}
Guild* ObjectMgr::GetGuildByGuildName(std::string guildName)
{
GuildMap::const_iterator itr;
for (itr = mGuild.begin();itr != mGuild.end(); itr++)
{
if( itr->second->GetGuildName() == guildName )
return itr->second;
}
return NULL;
}
void ObjectMgr::AddGMTicket(GM_Ticket *ticket,bool startup)
{
ASSERT( ticket );
GM_TicketList.push_back(ticket);
// save
if(!startup)
SaveGMTicket(ticket->guid);
}
//modified for vs2005 compatibility
void ObjectMgr::remGMTicket(uint64 guid)
{
for(GmTicketList::iterator i = GM_TicketList.begin(); i != GM_TicketList.end();)
{
if((*i)->guid == guid)
{
i = GM_TicketList.erase(i);
}
else
{
++i;
}
}
// kill from db
CharacterDatabase.Execute("DELETE FROM gm_tickets WHERE guid=%u", guid);
}
GM_Ticket* ObjectMgr::GetGMTicket(uint64 guid)
{
for(GmTicketList::iterator i = GM_TicketList.begin(); i != GM_TicketList.end(); i++)
{
if((*i)->guid == guid)
{
return (*i);
}
}
return NULL;
}
void ObjectMgr::LoadVendors()
{
HM_NAMESPACE::hash_map*>::const_iterator itr;
std::vector *items;
CreatureItem itm;
QueryResult *result = WorldDatabase.Query("SELECT * FROM vendors");
if(result)
{
do
{
Field *fields = result->Fetch();
itr = mVendors.find(fields[0].GetUInt32());
if (itr == mVendors.end())
{
items = new std::vector;
mVendors[fields[0].GetUInt32()] = items;
}
else
{
items = itr->second;
}
itm.itemid = fields[1].GetUInt32();
itm.amount = fields[2].GetUInt32();
items->push_back(itm);
}
while( result->NextRow() );
delete result;
}
Log.Notice("ObjectMgr", "%u vendors loaded.", mVendors.size());
}
std::vector* ObjectMgr::GetVendorList(uint32 entry)
{
return mVendors[entry];
}
void ObjectMgr::LoadTotemSpells()
{
std::stringstream query;
QueryResult *result = WorldDatabase.Query( "SELECT * FROM totemspells" );
if(!result)
{
return;
}
//TotemSpells *ts = NULL;
SpellEntry * sp;
uint32 spellid;
do
{
Field *fields = result->Fetch();
spellid = fields[1].GetUInt32();
sp = sSpellStore.LookupEntry(spellid);
if(!spellid || !sp) continue;
m_totemSpells.insert( TotemSpellMap::value_type( fields[0].GetUInt32(), sp ));
} while( result->NextRow() );
delete result;
Log.Notice("ObjectMgr", "%u totem spells loaded.", m_totemSpells.size());
}
SpellEntry* ObjectMgr::GetTotemSpell(uint32 spellId)
{
return m_totemSpells[spellId];
}
void ObjectMgr::LoadAIThreatToSpellId()
{
QueryResult *result = WorldDatabase.Query( "SELECT * FROM ai_threattospellid" );
if(!result)
{
return;
}
ThreatToSpellId *t2s = NULL;
do
{
Field *fields = result->Fetch();
t2s = new ThreatToSpellId;
t2s->spellId = fields[0].GetUInt32();
t2s->mod = atoi(fields[1].GetString());
threatToSpells.push_back(t2s);
} while( result->NextRow() );
delete result;
Log.Notice("ObjectMgr", "%u spell threats loaded.", threatToSpells.size());
}
int32 ObjectMgr::GetAIThreatToSpellId(uint32 spellId)
{
for(ThreadToSpellList::iterator i = threatToSpells.begin(); i != threatToSpells.end(); i++)
{
if((*i)->spellId == spellId)
{
return (*i)->mod;
}
}
return 0;
}
Item * ObjectMgr::CreateItem(uint32 entry,Player * owner)
{
ItemPrototype * proto = ItemPrototypeStorage.LookupEntry(entry);
if(proto == 0) return 0;
if(proto->InventoryType == INVTYPE_BAG)
{
Container * pContainer = new Container(HIGHGUID_CONTAINER,GenerateLowGuid(HIGHGUID_CONTAINER));
pContainer->Create( entry, owner);
pContainer->SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
return pContainer;
}
else
{
Item * pItem = new Item(HIGHGUID_ITEM,GenerateLowGuid(HIGHGUID_ITEM));
pItem->Create(entry, owner);
pItem->SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
return pItem;
}
}
Item * ObjectMgr::LoadItem(uint64 guid)
{
QueryResult * result = CharacterDatabase.Query("SELECT * FROM playeritems WHERE guid = %u", GUID_LOPART(guid));
Item * pReturn = 0;
if(result)
{
ItemPrototype * pProto = ItemPrototypeStorage.LookupEntry(result->Fetch()[2].GetUInt32());
if(!pProto)
return NULL;
if(pProto->InventoryType == INVTYPE_BAG)
{
Container * pContainer = new Container(HIGHGUID_CONTAINER,guid);
pContainer->LoadFromDB(result->Fetch());
pReturn = pContainer;
}
else
{
Item * pItem = new Item(HIGHGUID_ITEM,guid);
pItem->LoadFromDB(result->Fetch(), 0, false);
pReturn = pItem;
}
delete result;
}
return pReturn;
}
void ObjectMgr::LoadCorpses(MapMgr * mgr)
{
Corpse *pCorpse = NULL;
QueryResult *result = CharacterDatabase.Query("SELECT * FROM corpses WHERE instanceId = %u", mgr->GetInstanceID());
if(result)
{
do
{
Field *fields = result->Fetch();
pCorpse = new Corpse(HIGHGUID_CORPSE,fields[0].GetUInt32());
pCorpse->SetPosition(fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
pCorpse->SetZoneId(fields[5].GetUInt32());
pCorpse->SetMapId(fields[6].GetUInt32());
pCorpse->SetInstanceID(fields[7].GetUInt32());
pCorpse->LoadValues( fields[8].GetString());
if(pCorpse->GetUInt32Value(CORPSE_FIELD_DISPLAY_ID) == 0)
{
delete pCorpse;
continue;
}
pCorpse->PushToWorld(mgr);
} while( result->NextRow() );
delete result;
}
}
std::list* ObjectMgr::GetListForItemSet(uint32 setid)
{
return mItemSets[setid];
}
void ObjectMgr::CorpseAddEventDespawn(Corpse *pCorpse)
{
if(!pCorpse->IsInWorld())
delete pCorpse;
else
sEventMgr.AddEvent(pCorpse->GetMapMgr(), &MapMgr::EventCorpseDespawn, pCorpse->GetGUID(), EVENT_CORPSE_DESPAWN, 600000, 1,0);
}
void ObjectMgr::DespawnCorpse(uint64 Guid)
{
Corpse * pCorpse = objmgr.GetCorpse(Guid);
if(pCorpse == 0) // Already Deleted
return;
pCorpse->Despawn();
delete pCorpse;
}
void ObjectMgr::CorpseCollectorUnload()
{
CorpseMap::const_iterator itr;
_corpseslock.Acquire();
for (itr = m_corpses.begin(); itr != m_corpses.end();)
{
Corpse * c =itr->second;
++itr;
if(c->IsInWorld())
c->RemoveFromWorld();
delete c;
}
m_corpses.clear();
_corpseslock.Release();
}
GossipMenu::GossipMenu(uint64 Creature_Guid, uint32 Text_Id) : TextId(Text_Id), CreatureGuid(Creature_Guid)
{
}
void GossipMenu::AddItem(uint16 Icon, const char* Text, int32 Id)
{
GossipMenuItem Item;
Item.Icon = Icon;
Item.Text = Text;
Item.Id = Menu.size();
if(Id > 0)
Item.IntId = Id;
else
Item.IntId = Item.Id;
Menu.push_back(Item);
}
void GossipMenu::AddItem(GossipMenuItem* GossipItem)
{
Menu.push_back(*GossipItem);
}
void GossipMenu::BuildPacket(WorldPacket& Packet)
{
Packet << CreatureGuid;
Packet << TextId;
Packet << uint32(Menu.size());
for(std::vector::iterator iter = Menu.begin();
iter != Menu.end(); ++iter)
{
Packet << iter->Id;
Packet << iter->Icon;
Packet << uint32(0); // something new in tbc. maybe gold requirement or smth?
Packet << iter->Text;
Packet << uint8(0); // ?
}
}
void GossipMenu::SendTo(Player* Plr)
{
WorldPacket data(SMSG_GOSSIP_MESSAGE, Menu.size() * 50 + 12);
BuildPacket(data);
data << uint32(0); // 0 quests obviously
Plr->GetSession()->SendPacket(&data);
}
void ObjectMgr::CreateGossipMenuForPlayer(GossipMenu** Location, uint64 Guid, uint32 TextID, Player* Plr)
{
GossipMenu *Menu = new GossipMenu(Guid, TextID);
ASSERT(Menu);
if(Plr->CurrentGossipMenu != NULL)
delete Plr->CurrentGossipMenu;
Plr->CurrentGossipMenu = Menu;
*Location = Menu;
}
GossipMenuItem GossipMenu::GetItem(uint32 Id)
{
if(Id >= Menu.size())
{
GossipMenuItem k;
k.IntId = 1;
return k;
} else {
return Menu[Id];
}
}
uint32 ObjectMgr::GetGossipTextForNpc(uint32 ID)
{
return mNpcToGossipText[ID];
}
void ObjectMgr::GenerateTrainerSpells()
{
std::map OMap;
QueryResult * result = WorldDatabase.Query("SELECT * FROM trainerspelloverride");
if(result != 0)
{
// uint32 mx = result->GetRowCount(), c = 0;
do
{
Field * f = result->Fetch();
TrainerSpellOverride ov;
ov.Cost = f[1].GetUInt32();
ov.RequiredSpell = f[2].GetUInt32();
ov.DeleteSpell = f[3].GetUInt32();
ov.RequiredSkill = f[4].GetUInt32();
ov.RequiredSkillValue = f[5].GetUInt32();
ov.RequiredLevel = f[6].GetUInt32();
ov.RequiredClass = f[7].GetUInt32();
OMap[f[0].GetUInt32()] = ov;
} while(result->NextRow());
delete result;
}
std::vector itemSpell;
// Lets take item spell learn list so we can remove recipe from trainers
result = WorldDatabase.Query("SELECT spellid_1,spellid_2,spellid_3,spellid_4,spellid_5 FROM items");
if(result != 0)
{
do
{
Field * f = result->Fetch();
uint32 s1,s2,s3,s4,s5;
if((s1 = f[0].GetUInt32()) != 0)
{
SpellEntry *sp = sSpellStore.LookupEntry(s1);
for(int i = 0; i < 3; i++)
{
if(sp->Effect[i] == SPELL_EFFECT_LEARN_SPELL
|| sp->Effect[i] == SPELL_EFFECT_LEARN_PET_SPELL)
itemSpell.push_back(sp->EffectTriggerSpell[i]);
}
}
if((s2 = f[1].GetUInt32()) != 0)
{
SpellEntry *sp = sSpellStore.LookupEntry(s2);
for(int i = 0; i < 3; i++)
{
if(sp->Effect[i] == SPELL_EFFECT_LEARN_SPELL
|| sp->Effect[i] == SPELL_EFFECT_LEARN_PET_SPELL)
itemSpell.push_back(sp->EffectTriggerSpell[i]);
}
}
if((s3 = f[2].GetUInt32()) != 0)
{
SpellEntry *sp = sSpellStore.LookupEntry(s3);
for(int i = 0; i < 3; i++)
{
if(sp->Effect[i] == SPELL_EFFECT_LEARN_SPELL
|| sp->Effect[i] == SPELL_EFFECT_LEARN_PET_SPELL)
itemSpell.push_back(sp->EffectTriggerSpell[i]);
}
}
if((s4 = f[3].GetUInt32()) != 0)
{
SpellEntry *sp = sSpellStore.LookupEntry(s4);
for(int i = 0; i < 3; i++)
{
if(sp->Effect[i] == SPELL_EFFECT_LEARN_SPELL
|| sp->Effect[i] == SPELL_EFFECT_LEARN_PET_SPELL)
itemSpell.push_back(sp->EffectTriggerSpell[i]);
}
}
if((s5 = f[4].GetUInt32()) != 0)
{
SpellEntry *sp = sSpellStore.LookupEntry(s5);
for(int i = 0; i < 3; i++)
{
if(sp->Effect[i] == SPELL_EFFECT_LEARN_SPELL
|| sp->Effect[i] == SPELL_EFFECT_LEARN_PET_SPELL)
itemSpell.push_back(sp->EffectTriggerSpell[i]);
}
}
} while(result->NextRow());
delete result;
}
// Convert ranks into our temp map.
// i _hate_ string indexes :p
map* > SpellRankMap;
map SpellRanks;
map* >::iterator it1;
map::iterator it2;
map TeachingSpellMap;
uint32 mx = sSpellStore.GetNumRows();
for(uint32 i = 0; i < mx; ++i)
{
// Get Spell
SpellEntry *Sp = static_cast*>(SpellStore::getSingletonPtr())->LookupRow(i);
if(Sp != NULL)
{
// Skip learning spells ;)
// Skip any spells that are obselete
if(Sp->SpellVisual == 222)
continue;
uint32 j;
bool check = false;
for(j = 0; j < 3; j++)
{
if(check)
break;
check = false;
if(Sp->Effect[j] == SPELL_EFFECT_LEARN_SPELL ||
Sp->Effect[j] == SPELL_EFFECT_LEARN_PET_SPELL)
{
// BANNED SPELLS CUZ THEY'RE FUCKED.. GG BLIZZARD
if(Sp->Id == 21085 || Sp->Id == 1872)
continue;
// const char* SpellName = sSpellStore.LookupString(Sp->Name);
// const char* RankName = sSpellStore.LookupString(Sp->Rank);
if(!(TeachingSpellMap.find(Sp->EffectTriggerSpell[j]) == TeachingSpellMap.end()))
{
//printf("Duplicate training spell %s %s\n", SpellName, RankName);
} else {
for(std::vector::iterator itr = itemSpell.begin(); itr != itemSpell.end(); ++itr)
{
if((*itr) == Sp->Id)
{
check = true;
break;
}
}
if(check)
continue;
TeachingSpellMap.insert( map::value_type( Sp->EffectTriggerSpell[j], Sp->Id ) );
}
break;
}
}
if(j != 3)
continue;
// Get our row name
if(!Sp->Rank)
continue;
const char* SpellName = sSpellStore.LookupString(Sp->Name);
const char* RankName = sSpellStore.LookupString(Sp->Rank);
// Skip old spells
if(SpellName[0] == 'z' && SpellName[1] == 'z' &&
SpellName[2] == 'O' && SpellName[3] == 'L' &&
SpellName[4] == 'D')
{
continue;
}
if(m_disabled_trainer_spells.find(Sp->Id) != m_disabled_trainer_spells.end())
continue;
// Convert rank name into a number
int32 RankNumber = -1;
if(sscanf(RankName, "Rank %d", (int*)&RankNumber) != 1) // Not a ranked spell
continue;
SpellRanks[Sp->Id] = RankNumber;
// Insert into our map if we don't have one
string Sp_Name = SpellName;
it1 = SpellRankMap.find(Sp_Name);
map *mapPtr;
if(it1 == SpellRankMap.end())
{
mapPtr = new map;
SpellRankMap.insert( map* >::value_type( Sp_Name, mapPtr ) );
it1 = SpellRankMap.find(Sp_Name);
ASSERT(it1 != SpellRankMap.end());
} else {
mapPtr = it1->second;
}
if(!(mapPtr->find(RankNumber) == mapPtr->end()))
{
uint32 o = mapPtr->find(RankNumber)->second;
SpellEntry *p = sSpellStore.LookupEntry(o);
// const char* SpellName2 = sSpellStore.LookupString(p->Name);
// const char* RankName2 = sSpellStore.LookupString(p->Rank);
// For enchants, override the aura spell with casting spell.
if(Sp->Effect[0] == 54 ||
Sp->Effect[1] == 54 ||
Sp->Effect[2] == 54)
{
if(p->Effect[0] != 54 && p->Effect[1] != 54 && p->Effect[2] != 54)
mapPtr->find(RankNumber)->second = Sp->Id;
}
} else {
mapPtr->insert( map::value_type( (uint32)RankNumber, Sp->Id ) );
}
}
}
skilllinespell *sp;
SpellEntry * spell;
TrainerSpellMap * destmap;
mx = sSkillStore.GetNumRows();
for(uint32 i = 0; i < mx; ++i)
{
sp = sSkillStore.LookupEntry(i);
// Check if we're a learning spell :)
spell = sSpellStore.LookupEntry(sp->spell);
skilllineentry *skill = sSkillLineStore.LookupEntry(sp->skilline);
ASSERT(skill);
for(uint32 j = 0; j < 3; j++)
{
destmap = NULL;
uint32 TeachingSpellId = TeachingSpellMap[sp->spell];
if(!TeachingSpellId)
continue;
SpellEntry * TeachingSpell = sSpellStore.LookupEntry(TeachingSpellId);
SpellEntry * TeachingSpell2 = NULL;//2nd level teaching spell used by Pet trainers to teach hunter a teaching spell
uint32 TeachingSpellId2 = 0;//init 0, later used to distinguish if 2nd lvl teach.sp. is present
if((TeachingSpell->Effect[j] == SPELL_EFFECT_LEARN_SPELL && TeachingSpell->EffectImplicitTargetA[j]==5) || TeachingSpell->Effect[j] == SPELL_EFFECT_LEARN_PET_SPELL )
{
destmap = &mPetSpells;
TeachingSpellId2 = TeachingSpellMap[TeachingSpellId];
if(TeachingSpellId2)
TeachingSpell2 = sSpellStore.LookupEntry(TeachingSpellId2);
}
else if(TeachingSpell->Effect[j] == SPELL_EFFECT_LEARN_SPELL)
destmap = &mNormalSpells;
if(destmap == NULL)
continue;
// TODO: Check for quest reward spells, and shit like that.
uint32 SpellID = TeachingSpell->EffectTriggerSpell[j];
TrainerSpell * TS = new TrainerSpell;
TS->pSpell = spell;
TS->pTrainingSpell = TeachingSpellId2 ? TeachingSpell2 : TeachingSpell;
TS->SpellID = TeachingSpellId2 ? TeachingSpell2->EffectTriggerSpell[0] : SpellID;
TS->TeachingSpellID = TeachingSpellId2 ? TeachingSpellId2 : TeachingSpellId;
TS->DeleteSpell = 0;
TS->RequiredSpell = 0;
TS->TeachingLine = 0;
TS->IsProfession = 0;
TS->RequiredClass = -1;
// Find out our spell rank.
const char* SpellName = sSpellStore.LookupString(spell->Name);
const char* RankName = sSpellStore.LookupString(spell->Rank);
string Sp_Name = SpellName;
it1 = SpellRankMap.find(Sp_Name);
if(it1 != SpellRankMap.end())
{
// We're a ranked spell.
uint32 SpellRank = SpellRanks[SpellID];
// Grab any ranks lower than ours
if(SpellRank > 1)
{
vector lowerspells;
lowerspells.reserve(15);
// Assign required spells
uint32 crank = SpellRank - 1;
if(crank > 0)
{
it2 = it1->second->find(crank);
if((it2 != it1->second->end()))
{
uint32 rspell = it2->second;
if(TeachingSpellId2)
rspell = 0;
else
ASSERT(rspell);
TS->RequiredSpell = rspell;
uint32 flags = spell->SpellFamilyName;
if(flags == 0x4 || flags == 0x10 || flags == 0x8 || flags == 0xA)
TS->DeleteSpell = TeachingSpellId2 ? 0 : rspell; //do not delete lower ranks of pet spells
}
}
}
}
// Profession checks.. la di da...
TS->RequiredSkillLine = 0;
TS->RequiredSkillLineValue = 0;
TS->RequiredLevel = spell->spellLevel;
TS->Cost = sWorld.mPrices[spell->spellLevel];
if(skill->type == SKILL_TYPE_PROFESSION)
{
// Check if we're a profession learner. If we are, we need to have the previous
// rank. If we're a profession spell, we need to have an amount
uint32 l;
for(l = 0; l < 3; ++l)
{
if(TeachingSpell->Effect[l] == SPELL_EFFECT_SKILL_STEP) // Rank
{
break;
}
}
if(l == 3)
{
//TS->RequiredSkillLineValue = 1;
//TS->RequiredSkillLineValue = sp->minrank ? sp->minrank : 1;
if(sp->green)
TS->RequiredSkillLineValue = (sp->green >= 30) ? (sp->green - 30) : sp->green;
else
TS->RequiredSkillLineValue = 1;
TS->RequiredSkillLine = skill->id;
}
else
{
//Here handles general profession learns
TS->TeachingLine = skill->id;
uint32 rval = 0;
// hack hack hack!
if(!stricmp(RankName, "Journeyman"))
rval = 75;
else if(!stricmp(RankName, "Expert"))
rval = 150;
else if(!stricmp(RankName, "Artisan"))
rval = 225;
else if(!stricmp(RankName, "Master"))
rval = 300;
else
TS->IsProfession = 1;
if(rval != 0)
{
TS->RequiredSkillLine = skill->id;
TS->RequiredSkillLineValue = rval;
}
}
}
if(skill->type == SKILL_TYPE_SECONDARY)
{
uint32 rval = 0;
//Riding skills again
if(strstr(SpellName, "Riding") || strstr(SpellName, "Piloting")
|| strstr(SpellName, "Horsemanship"))
{
if(!stricmp(RankName, "Apprentice"))
{
TS->Cost = 900000;
TS->RequiredLevel = 40;
}
else if(!stricmp(RankName, "Journeyman"))
{
rval = 75;
TS->Cost = 6000000;
TS->RequiredLevel = 60;
}
else if(!stricmp(RankName, "Expert"))
{
rval = 150;
TS->Cost = 8000000;
TS->RequiredLevel = 70;
}
else if(!stricmp(RankName, "Artisan"))
{
rval = 225;
TS->Cost = 50000000;
TS->RequiredLevel = 70;
}
//No Master for now but if we have later
else if(!stricmp(RankName, "Master"))
{
rval = 300;
TS->RequiredLevel = 70;
TS->Cost = 90000000;
}
else//No old shit
{
delete TS;
break;
}
}
if(rval != 0)
{
TS->RequiredSkillLine = skill->id;
TS->RequiredSkillLineValue = rval;
}
}
std::map::iterator oitr = OMap.find(TS->TeachingSpellID);
if(oitr == OMap.end()) oitr = OMap.find(TS->SpellID);
if(oitr != OMap.end())
{
TrainerSpellOverride * ov = &oitr->second;
TS->Cost = ov->Cost ? ov->Cost : TS->Cost;
TS->RequiredClass = ov->RequiredClass ? ov->RequiredClass : TS->RequiredClass;
TS->RequiredSpell = ov->RequiredSpell ? ov->RequiredSpell : TS->RequiredSpell;
TS->RequiredSkillLine = ov->RequiredSkill ? ov->RequiredSkill : TS->RequiredSkillLine;
TS->RequiredSkillLineValue = ov->RequiredSkillValue ? ov->RequiredSkillValue : TS->RequiredSkillLineValue;
TS->DeleteSpell = ov->DeleteSpell ? ov->DeleteSpell : TS->DeleteSpell;
TS->RequiredLevel = ov->RequiredLevel ? ov->RequiredLevel : TS->RequiredLevel;
TS->RequiredClass = ov->RequiredClass ? ov->RequiredClass : TS->RequiredClass;
}
if(skill->type == SKILL_TYPE_PROFESSION || skill->type == SKILL_TYPE_SECONDARY)
{
if(skill->type == SKILL_TYPE_SECONDARY)
{
if(skill->id == 185 || skill->id == 129 || skill->id == 356)
{
if(sp->next == 0 && TS->RequiredSkillLineValue <= 1)
{
delete TS;
continue;
}
}
}
else
{
if(TS->IsProfession != 1 && TS->RequiredSkillLineValue <= 1)
{
delete TS;
continue;
}
}
}
if(m_disabled_trainer_spells.find( TS->pSpell->Id ) != m_disabled_trainer_spells.end() ||
m_disabled_trainer_spells.find( TS->pTrainingSpell->Id ) != m_disabled_trainer_spells.end())
{
delete TS;
continue;
}
TrainerSpellMap::iterator iter = destmap->find(sp->skilline);
if(iter == destmap->end())
{
vector v;
v.push_back(TS);
destmap->insert( TrainerSpellMap::value_type( sp->skilline, v ) );
//const char* skillname = sSkillLineStore.LookupString(skill->Name);
/*printf("Skill line: %s created for %s.\n", skillname,
( destmap == &mNormalSpells ? "NORMAL" : "PET"));*/
} else {
iter->second.push_back(TS);
}
}
}
// Cleanup
for(it1 = SpellRankMap.begin(); it1 != SpellRankMap.end(); ++it1)
{
it1->second->clear();
delete it1->second;
}
TrainerSpell * tsp = new TrainerSpell;
tsp->TeachingSpellID = 1579;
tsp->SpellID = 1515;
tsp->Cost = 300;
tsp->DeleteSpell=0;
tsp->pSpell = sSpellStore.LookupEntry(1515);
tsp->IsProfession=0;
tsp->pTrainingSpell = sSpellStore.LookupEntry(1579);
tsp->RequiredLevel=10;
tsp->RequiredSkillLine=0;
tsp->RequiredSpell=0;
tsp->SpellRank=0;
tsp->TeachingLine=0;
tsp->SpellType=0;
tsp->RequiredClass=-1;
//1579 - tame beast
mNormalSpells.find(50)->second.push_back(tsp);
SpellRankMap.clear();
}
void ObjectMgr::LoadTrainers()
{
LoadDisabledSpells();
GenerateTrainerSpells();
QueryResult * result = WorldDatabase.Query("SELECT * FROM trainers");
if(!result) return;
// uint32 mx = result->GetRowCount();
// uint32 c = 0;
uint32 entry, maxlevel, class_;
uint32 skilllines[20];
skilllineentry *skill;
do
{
Field * fields = result->Fetch();
entry = fields[0].GetUInt32();
Trainer * tr = new Trainer;
tr->IsSimpleTrainer = false;
tr->TrainerType = 0;
tr->TrainMsg = 0;
tr->NoTrainMsg = 0;
tr->TalkMessage = 0;
for(uint32 i = 0; i < 20; ++i)
{
skilllines[i] = fields[1+i].GetUInt32();
skill = sSkillLineStore.LookupEntry(skilllines[i]);
if(!skill)
{
skilllines[i] = 0;
continue;
}
if(skill->type == SKILL_TYPE_PROFESSION ||
skill->type == SKILL_TYPE_SECONDARY)
{
tr->TrainerType = 2;
}
}
maxlevel = fields[21].GetUInt32();
class_ = fields[22].GetUInt32();
vector tmp;
tmp.reserve(400);
for(uint32 i = 0; i < 20; ++i)
{
if(skilllines[i] != 0)
{
//TODO: Check for pet trainer!
TrainerSpellMap::iterator iter = mNormalSpells.find(skilllines[i]);
if(iter == mNormalSpells.end())
{
iter = mPetSpells.find(skilllines[i]);
if(iter == mPetSpells.end()) // Not found.
continue;
}
for(vector::iterator it = iter->second.begin();
it != iter->second.end(); ++it)
{
if((*it)->pSpell->spellLevel <= maxlevel || maxlevel == 60) // 60 trainers have all?
{
skill = sSkillLineStore.LookupEntry(skilllines[i]);
if(skill->type == SKILL_TYPE_PROFESSION || skill->type == SKILL_TYPE_SECONDARY)
{
if(skill->type == SKILL_TYPE_SECONDARY)
{
if(skill->id == 185 || skill->id == 129 || skill->id == 356)
{
bool add = AddTrainerSpell(entry, (*it)->pSpell);
if(add)
tmp.push_back((*it));
}
else
{
tmp.push_back((*it));
}
}
else
{
bool add = AddTrainerSpell(entry, (*it)->pSpell);
if(add)
tmp.push_back((*it));
}
}
else
tmp.push_back((*it));
}
}
}
}
tr->SpellCount = tmp.size();
tr->SpellList = new TrainerSpell*[tmp.size()];
uint32 j = 0;
for(vector::iterator it = tmp.begin();
it != tmp.end(); ++it, j++)
{
tr->SpellList[j] = (*it);
}
const char * temp = fields[23].GetString();
tr->TalkMessage = new char[strlen(temp)+1];
strcpy(tr->TalkMessage, temp);
tr->TalkMessage[strlen(temp)] = 0;
tr->RequiredClass = class_;
//assert(mTrainers.find(entry) == mTrainers.end());
if(mTrainers.find(entry) != mTrainers.end())
{
delete [] tr->TalkMessage;
delete [] tr->SpellList;
delete tr;
continue;
}
mTrainers.insert( TrainerMap::value_type( entry, tr ) );
} while(result->NextRow());
delete result;
//simple trainer generation
result = WorldDatabase.Query("SELECT * FROM trainer_defs");
if(!result) return;
do
{
Field * fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
if(mTrainers.find(entry) != mTrainers.end())
{
continue;
}
Trainer * tr = new Trainer;
tr->IsSimpleTrainer = 1;
tr->Req_rep = fields[1].GetUInt32();
tr->Req_rep_value = fields[2].GetUInt32();
tr->RequiredClass = fields[3].GetUInt32();
tr->Req_lvl = fields[4].GetUInt32();
tr->TrainerType = fields[5].GetUInt32(); //0 or 2 ?
const char * temp = fields[6].GetString();
int len=strlen(temp);
if(len)
{
tr->TrainMsg = new char[len+1];
strcpy(tr->TrainMsg, temp);
tr->TrainMsg[len] = 0;
}
else tr->TrainMsg=NULL;
temp = fields[7].GetString();
len=strlen(temp);
if(len)
{
tr->NoTrainMsg = new char[len+1];
strcpy(tr->NoTrainMsg, temp);
tr->NoTrainMsg[len] = 0;
}
else tr->NoTrainMsg=NULL;
//get spell list count
QueryResult * result2 = WorldDatabase.Query("SELECT count(entry) FROM trainer_spells where entry='%d'",entry);
Field *fields2 = result2->Fetch();
tr->SpellCount = fields2[0].GetUInt32();
tr->SpellList = new TrainerSpell*[tr->SpellCount];
delete result2;
//now load the spells
result2 = WorldDatabase.Query("SELECT * FROM trainer_spells where entry='%d'",entry);
uint32 badspellcount=0;
for(int i=0;iSpellCount;i++)
{
fields2 = result2->Fetch();
if(!fields2)
break;//wow, this is bad, a few seconds ago we had all entrys
uint32 CastSpellID=fields2[1].GetUInt32();
SpellEntry *spellInfo = sSpellStore.LookupEntry(CastSpellID );
if(!spellInfo)
{
badspellcount++;
result2->NextRow();
continue; //omg a bad spell !
}
tr->SpellList[i] = new TrainerSpell;
tr->SpellList[i]->TeachingSpellID = CastSpellID;
tr->SpellList[i]->Cost = fields2[2].GetUInt32();
tr->SpellList[i]->RequiredSpell = fields2[3].GetUInt32();
tr->SpellList[i]->RequiredSkillLine = fields2[4].GetUInt32();
tr->SpellList[i]->RequiredSkillLineValue = fields2[5].GetUInt32();
tr->SpellList[i]->RequiredLevel = fields2[6].GetUInt32();
tr->SpellList[i]->DeleteSpell = fields2[7].GetUInt32();
tr->SpellList[i]->IsProfession = fields2[8].GetUInt32();
//some spells might teach us more then 1 spell. Just have no idea how we should handle those. Maybe later it will get clear to us
uint32 teachspell=0;
uint32 Profession_ranking=0;
uint32 is_profeciency=0;//don't report spells like these as faulty spells
for(int k=0;k<3;k++)
{
if(spellInfo->Effect[k]==SPELL_EFFECT_LEARN_SPELL)
{
teachspell = spellInfo->EffectTriggerSpell[k];
tr->SpellList[i]->TeachSpellID = spellInfo->EffectTriggerSpell[k];
// break;
}
else if(spellInfo->Effect[k]==SPELL_EFFECT_SKILL_STEP)
{
Profession_ranking = spellInfo->EffectBasePoints[k]+1;
// break;
}
}
if(teachspell)
{
SpellEntry *spellInfo2 = sSpellStore.LookupEntry(teachspell );
if(spellInfo2)
tr->SpellList[i]->SpellRank = spellInfo2->spellLevel;
if(Profession_ranking && spellInfo2->spellLevel==0)
{
tr->SpellList[i]->SpellRank = Profession_ranking;
spellInfo2->spellLevel = Profession_ranking; //stupid profession spells have no ranking :S
}
// if((!spellInfo2 && !Profession_ranking) || tr->SpellList[i]->SpellRank==0)
// {
//do not report proficiency spells, these do not have a level
// if( (spellInfo2 && !( spellInfo2->Effect[0]==SPELL_EFFECT_PROFICIENCY || spellInfo2->Effect[1]==SPELL_EFFECT_PROFICIENCY || spellInfo2->Effect[2]==SPELL_EFFECT_PROFICIENCY))
// || !spellInfo2)
// sLog.outDebug("This is a faulty trainer spell, please report it to devs : %u \n",CastSpellID);
// }
}
else
{
// sLog.outDebug("OMG trainer is casting a spell that does not teach anything : %u \n",CastSpellID);
}
result2->NextRow();
}
delete result2;
//in case we encountered another noob who can't assemble a train list
tr->SpellCount -= badspellcount;
//and now we insert it to our lookup table
if(!tr->SpellCount)
{
delete [] tr->TrainMsg;
delete [] tr->NoTrainMsg;
delete [] tr->SpellList;
delete tr;
continue;
}
mTrainers.insert( TrainerMap::value_type( entry, tr ) );
} while(result->NextRow());
delete result;
Log.Notice("ObjectMgr", "%u trainers loaded.", mTrainers.size());
}
bool ObjectMgr::AddTrainerSpell(uint32 entry, SpellEntry *pSpell)
{
CreatureInfo *ci = CreatureNameStorage.LookupEntry(entry);
if(ci)
{
const char* RankName = sSpellStore.LookupString(pSpell->Rank);
if(strstr(ci->SubName,"Journeyman"))
{
if(!stricmp(RankName, "Journeyman"))
return true;
else if(!stricmp(RankName, "Expert"))
return false;
else if(!stricmp(RankName, "Artisan"))
return false;
else if(!stricmp(RankName, "Master"))
return false;
else
return true;
}
else if(strstr(ci->SubName,"Expert"))
{
if(!stricmp(RankName, "Journeyman"))
return true;
else if(!stricmp(RankName, "Expert"))
return true;
else if(!stricmp(RankName, "Artisan"))
return false;
else if(!stricmp(RankName, "Master"))
return false;
else
return true;
}
else if(strstr(ci->SubName,"Artisan"))
{
if(!stricmp(RankName, "Journeyman"))
return true;
else if(!stricmp(RankName, "Expert"))
return true;
else if(!stricmp(RankName, "Artisan"))
return true;
else if(!stricmp(RankName, "Master"))
return false;
else
return true;
}
else
return true;
}
else
return false;
}
Trainer* ObjectMgr::GetTrainer(uint32 Entry)
{
TrainerMap::iterator iter = mTrainers.find(Entry);
if(iter == mTrainers.end())
return NULL;
return iter->second;
}
void ObjectMgr::GenerateLevelUpInfo()
{
// Generate levelup information for each class.
PlayerCreateInfo * PCI;
for(uint32 Class = WARRIOR; Class <= DRUID; ++Class)
{
// These are empty.
if(Class == 10 || Class == 6)
continue;
// Search for a playercreateinfo.
for(uint32 Race = RACE_HUMAN; Race <= RACE_DRAENEI; ++Race )
{
PCI = GetPlayerCreateInfo(Race, Class);
if(PCI == 0)
continue; // Class not valid for this race.
// Generate each level's information
uint32 MaxLevel = sWorld.Expansion1LevelCap + 1;
LevelInfo* lvl=0, lastlvl;
lastlvl.HP = PCI->health;
lastlvl.Mana = PCI->mana;
lastlvl.Stat[0] = PCI->strength;
lastlvl.Stat[1] = PCI->ability;
lastlvl.Stat[2] = PCI->stamina;
lastlvl.Stat[3] = PCI->intellect;
lastlvl.Stat[4] = PCI->spirit;
lastlvl.XPToNextLevel = 400;
LevelMap * lMap = new LevelMap;
// Create first level.
lvl = new LevelInfo;
*lvl = lastlvl;
// Insert into map
lMap->insert( LevelMap::value_type( 1, lvl ) );
uint32 val;
for(uint32 Level = 2; Level < MaxLevel; ++Level)
{
lvl = new LevelInfo;
// Calculate Stats
for(uint32 s = 0; s < 5; ++s)
{
val = GainStat(Level, Class, s);
lvl->Stat[s] = lastlvl.Stat[s] + val;
}
// Calculate HP/Mana
uint32 TotalHealthGain = 0;
uint32 TotalManaGain = 0;
switch(Class)
{
case WARRIOR:
if(Level<13)TotalHealthGain+=19;
else if(Level <36) TotalHealthGain+=Level+6;
// else if(Level >60) TotalHealthGain+=Level+100;
else if(Level >60) TotalHealthGain+=Level+206;
else TotalHealthGain+=2*Level-30;
break;
case HUNTER:
if(Level<13)TotalHealthGain+=17;
// else if(Level >60) TotalHealthGain+=Level+45;
else if(Level >60) TotalHealthGain+=Level+161;
else TotalHealthGain+=Level+4;
if(Level<11)TotalManaGain+=29;
else if(Level<27)TotalManaGain+=Level+18;
// else if(Level>60)TotalManaGain+=Level+20;
else if(Level>60)TotalManaGain+=Level+150;
else TotalManaGain+=45;
break;
case ROGUE:
if(Level <15)TotalHealthGain+=17;
// else if(Level >60) TotalHealthGain+=Level+110;
else if(Level >60) TotalHealthGain+=Level+191;
else TotalHealthGain+=Level+2;
break;
case DRUID:
if(Level < 17)TotalHealthGain+=17;
// else if(Level >60) TotalHealthGain+=Level+55;
else if(Level >60) TotalHealthGain+=Level+176;
else TotalHealthGain+=Level;
if(Level < 26)TotalManaGain+=Level+20;
// else if(Level>60)TotalManaGain+=Level+25;
else if(Level>60)TotalManaGain+=Level+150;
else TotalManaGain+=45;
break;
case MAGE:
if(Level < 23)TotalHealthGain+=15;
// else if(Level >60) TotalHealthGain+=Level+40;
else if(Level >60) TotalHealthGain+=Level+190;
else TotalHealthGain+=Level-8;
if(Level <28)TotalManaGain+=Level+23;
// else if(Level>60)TotalManaGain+=Level+26;
else if(Level>60)TotalManaGain+=Level+115;
else TotalManaGain+=51;
break;
case SHAMAN:
if(Level <16)TotalHealthGain+=17;
// else if(Level >60) TotalHealthGain+=Level+75;
else if(Level >60) TotalHealthGain+=Level+157;
else TotalHealthGain+=Level+1;
if(Level<22)TotalManaGain+=Level+19;
// else if(Level>60)TotalManaGain+=Level+70;
else if(Level>60)TotalManaGain+=Level+175;
else TotalManaGain+=49;
break;
case WARLOCK:
if(Level <17)TotalHealthGain+=17;
// else if(Level >60) TotalHealthGain+=Level+50;
else if(Level >60) TotalHealthGain+=Level+192;
else TotalHealthGain+=Level-2;
if(Level< 30)TotalManaGain+=Level+21;
// else if(Level>60)TotalManaGain+=Level+25;
else if(Level>60)TotalManaGain+=Level+121;
else TotalManaGain+=51;
break;
case PALADIN:
if(Level < 14)TotalHealthGain+=18;
// else if(Level >60) TotalHealthGain+=Level+55;
else if(Level >60) TotalHealthGain+=Level+167;
else TotalHealthGain+=Level+4;
if(Level<30)TotalManaGain+=Level+17;
// else if(Level>60)TotalManaGain+=Level+100;
else if(Level>60)TotalManaGain+=Level+131;
else TotalManaGain+=42;
break;
case PRIEST:
if(Level <21)TotalHealthGain+=15;
// else if(Level >60) TotalHealthGain+=Level+40;
else if(Level >60) TotalHealthGain+=Level+157;
else TotalHealthGain+=Level-6;
if(Level <22)TotalManaGain+=Level+22;
else if(Level <32)TotalManaGain+=Level+37;
// else if(Level>60)TotalManaGain+=Level+35;
else if(Level>60)TotalManaGain+=Level+207;
else TotalManaGain+=54;
break;
}
// Apply HP/Mana
lvl->HP = lastlvl.HP + TotalHealthGain;
lvl->Mana = lastlvl.Mana + TotalManaGain;
// Calculate next level XP
uint32 nextLvlXP = 0;
/* if( Level > 0 && Level <= 30 )
{
nextLvlXP = ((int)((((double)(8 * Level * ((Level * 5) + 45)))/100)+0.5))*100;
}
else if( Level == 31 )
{
nextLvlXP = ((int)((((double)(((8 * Level) + 3) * ((Level * 5) + 45)))/100)+0.5))*100;
}
else if( Level == 32 )
{
nextLvlXP = ((int)((((double)(((8 * Level) + 6) * ((Level * 5) + 45)))/100)+0.5))*100;
}
else
{
nextLvlXP = ((int)((((double)(((8 * Level) + ((Level - 30) * 5)) * ((Level * 5) + 45)))/100)+0.5))*100;
}*/
//this is a fixed table taken from 2.3.0 wow. This can;t get more blizzlike with the "if" cases ;)
if((Level-1)XPToNextLevel = nextLvlXP;
lastlvl = *lvl;
lastlvl.HP = lastlvl.HP;
// Apply to map.
lMap->insert( LevelMap::value_type( Level, lvl ) );
}
// Now that our level map is full, let's create the class/race pair
pair p;
p.first = Race;
p.second = Class;
// Insert back into the main map.
mLevelInfo.insert( LevelInfoMap::value_type( p, lMap ) );
}
}
Log.Notice("ObjectMgr", "%u level up informations generated.", mLevelInfo.size());
}
LevelInfo* ObjectMgr::GetLevelInfo(uint32 Race, uint32 Class, uint32 Level)
{
// Iterate levelinfo map until we find the right class+race.
LevelInfoMap::iterator itr = mLevelInfo.begin();
for(; itr != mLevelInfo.end(); ++itr)
{
if(itr->first.first == Race &&
itr->first.second == Class)
{
// We got a match.
// Let's check that our level is valid first.
if(Level > sWorld.Expansion1LevelCap) // too far.
Level = sWorld.Expansion1LevelCap;
// Pull the level information from the second map.
LevelMap::iterator it2 = itr->second->find(Level);
ASSERT(it2 != itr->second->end());
return it2->second;
}
}
return NULL;
}
void ObjectMgr::LoadDefaultPetSpells()
{
QueryResult * result = WorldDatabase.Query("SELECT * FROM petdefaultspells");
if(result)
{
do
{
Field * f = result->Fetch();
uint32 Entry = f[0].GetUInt32();
uint32 spell = f[1].GetUInt32();
SpellEntry * sp = sSpellStore.LookupEntry(spell);
if(spell && Entry && sp)
{
PetDefaultSpellMap::iterator itr = mDefaultPetSpells.find(Entry);
if(itr != mDefaultPetSpells.end())
itr->second.insert(sp);
else
{
set s;
s.insert(sp);
mDefaultPetSpells[Entry] = s;
}
}
} while(result->NextRow());
delete result;
}
}
set* ObjectMgr::GetDefaultPetSpells(uint32 Entry)
{
PetDefaultSpellMap::iterator itr = mDefaultPetSpells.find(Entry);
if(itr == mDefaultPetSpells.end())
return 0;
return &(itr->second);
}
void ObjectMgr::LoadPetSpellCooldowns()
{
DBCFile dbc;
dbc.open("DBC/CreatureSpellData.dbc");
uint32 SpellId;
uint32 Cooldown;
for(uint32 i = 0; i < dbc.getRecordCount(); ++i)
{
for(uint32 j = 0; j < 3; ++j)
{
SpellId = dbc.getRecord(i).getUInt(1 + j);
Cooldown = dbc.getRecord(i).getUInt(5 + j);
Cooldown *= 10;
if(SpellId)
{
PetSpellCooldownMap::iterator itr = mPetSpellCooldowns.find(SpellId);
if(itr == mPetSpellCooldowns.end())
{
mPetSpellCooldowns.insert( make_pair(SpellId, Cooldown) );
}
else
{
uint32 SP2 = mPetSpellCooldowns[SpellId];
ASSERT(Cooldown == SP2);
}
}
}
}
}
uint32 ObjectMgr::GetPetSpellCooldown(uint32 SpellId)
{
PetSpellCooldownMap::iterator itr = mPetSpellCooldowns.find(SpellId);
if(itr != mPetSpellCooldowns.end())
return itr->second;
return 0;
}
void ObjectMgr::LoadSpellFixes()
{
// Loads data from stored 1.12 dbc to fix spells that have had spell data removed in 2.0.
QueryResult * result = WorldDatabase.Query("SELECT * FROM spells112");
if(result == 0) return;
// uint32 count = result->GetRowCount();
// uint32 counter = 0;
uint32 fixed_count = 0;
uint32 proc_chance;
do
{
Field * fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
SpellEntry * sp = sSpellStore.LookupEntry(entry);
if(sp == 0) continue;
// FIX SPELL GROUP RELATIONS
{
uint32 sgr[3];
sgr[0] = fields[103].GetUInt32();
sgr[1] = fields[104].GetUInt32();
sgr[2] = fields[105].GetUInt32();
proc_chance = fields[25].GetUInt32();
for(uint32 i = 0; i < 3; ++i)
{
if(sgr[i] && sp->EffectSpellGroupRelation[i] == 0)
{
//string name = fields[120].GetString();
//printf("%s[%u] %u->%u\n", name.c_str(),i, sp->EffectSpellGroupRelation[i], sgr[i]);
sp->EffectSpellGroupRelation[i] = sgr[i];
++fixed_count;
}
}
sp->procChance = min(proc_chance, sp->procChance);
}
// FIX OTHER STUFF.. we'll find out..
} while(result->NextRow());
delete result;
Log.Notice("ObjectMgr", "%u spell fixes loaded.", fixed_count);
}
void ObjectMgr::LoadSpellOverride()
{
// int i = 0;
std::stringstream query;
QueryResult *result = WorldDatabase.Query( "SELECT DISTINCT overrideId FROM spelloverride" );
if(!result)
{
return;
}
// int num = 0;
// uint32 total =(uint32) result->GetRowCount();
SpellEntry * sp;
uint32 spellid;
do
{
Field *fields = result->Fetch();
query.rdbuf()->str("");
query << "SELECT spellId FROM spelloverride WHERE overrideId = ";
query << fields[0].GetUInt32();
QueryResult *resultIn = WorldDatabase.Query(query.str().c_str());
std::list* list = new std::list;
if(resultIn)
{
do
{
Field *fieldsIn = resultIn->Fetch();
spellid = fieldsIn[0].GetUInt32();
sp = sSpellStore.LookupEntry(spellid);
if(!spellid || !sp)
continue;
list->push_back(sp);
}while(resultIn->NextRow());
}
delete resultIn;
if(list->size() == 0)
delete list;
else
mOverrideIdMap.insert( OverrideIdMap::value_type( fields[0].GetUInt32(), list ));
} while( result->NextRow() );
delete result;
Log.Notice("ObjectMgr", "%u spell overrides loaded.", mOverrideIdMap.size());
}
void ObjectMgr::SetVendorList(uint32 Entry, std::vector* list_)
{
mVendors[Entry] = list_;
}
Creature * ObjectMgr::GetCreatureBySqlId(uint32 Sql_Id)
{
CreatureSqlIdMapMutex.Acquire();
Creature * c;
CreatureSqlIdMap::iterator itr = mCreatureSqlIds.find(Sql_Id);
c = (itr == mCreatureSqlIds.end()) ? 0 : itr->second;
CreatureSqlIdMapMutex.Release();
return c;
}
void ObjectMgr::SetCreatureBySqlId(uint32 Sql_Id, Creature * pCreature)
{
CreatureSqlIdMapMutex.Acquire();
if(pCreature != 0)
mCreatureSqlIds[Sql_Id] = pCreature;
else
{
CreatureSqlIdMap::iterator itr = mCreatureSqlIds.find(Sql_Id);
if(itr != mCreatureSqlIds.end())
mCreatureSqlIds.erase(itr);
}
CreatureSqlIdMapMutex.Release();
}
void ObjectMgr::LoadCreatureWaypoints()
{
QueryResult *result = WorldDatabase.Query("SELECT * FROM creature_waypoints");
if(!result)return;
do
{
Field *fields = result->Fetch();
WayPoint* wp = new WayPoint;
wp->id = fields[1].GetUInt32();
wp->x = fields[2].GetFloat();
wp->y = fields[3].GetFloat();
wp->z = fields[4].GetFloat();
wp->waittime = fields[5].GetUInt32();
wp->flags = fields[6].GetUInt32();
wp->forwardemoteoneshot = fields[7].GetBool();
wp->forwardemoteid = fields[8].GetUInt32();
wp->backwardemoteoneshot = fields[9].GetBool();
wp->backwardemoteid = fields[10].GetUInt32();
wp->forwardskinid = fields[11].GetUInt32();
wp->backwardskinid = fields[12].GetUInt32();
HM_NAMESPACE::hash_map::const_iterator i;
uint32 spawnid=fields[0].GetUInt32();
i=m_waypoints.find(spawnid);
if(i==m_waypoints.end())
{
WayPointMap* m=new WayPointMap;
if(m->size() <= wp->id)
m->resize(wp->id+1);
(*m)[wp->id]=wp;
m_waypoints[spawnid]=m;
}else
{
if(i->second->size() <= wp->id)
i->second->resize(wp->id+1);
(*(i->second))[wp->id]=wp;
}
}while( result->NextRow() );
Log.Notice("ObjectMgr", "%u waypoints cached.", result->GetRowCount());
delete result;
}
WayPointMap*ObjectMgr::GetWayPointMap(uint32 spawnid)
{
HM_NAMESPACE::hash_map::const_iterator i;
i=m_waypoints.find(spawnid);
if(i!=m_waypoints.end())
{
WayPointMap * m=i->second;
// we don't wanna erase from the map, becuase some are used more
// than once (for instances)
//m_waypoints.erase(i);
return m;
}
else return NULL;
}
Pet * ObjectMgr::CreatePet()
{
uint32 guid;
m_petlock.Acquire();
guid =++m_hiPetGuid;
m_petlock.Release();
return new Pet(HIGHGUID_PET,guid);
}
Player * ObjectMgr::CreatePlayer()
{
uint32 guid;
m_playerguidlock.Acquire();
guid =++m_hiPlayerGuid;
m_playerguidlock.Release();
return new Player(HIGHGUID_PLAYER,guid);
}
void ObjectMgr::AddPlayer(Player * p)//add it to global storage
{
_playerslock.AcquireWriteLock();
_players[p->GetGUIDLow()] = p;
_playerslock.ReleaseWriteLock();
}
void ObjectMgr::RemovePlayer(Player * p)
{
_playerslock.AcquireWriteLock();
_players.erase(p->GetGUIDLow());
_playerslock.ReleaseWriteLock();
}
Corpse * ObjectMgr::CreateCorpse()
{
uint32 guid;
m_corpseguidlock.Acquire();
guid =++m_hiCorpseGuid;
m_corpseguidlock.Release();
return new Corpse(HIGHGUID_CORPSE,guid);
}
void ObjectMgr::AddCorpse(Corpse * p)//add it to global storage
{
_corpseslock.Acquire();
m_corpses[p->GetGUIDLow()]=p;
_corpseslock.Release();
}
void ObjectMgr::RemoveCorpse(Corpse * p)
{
_corpseslock.Acquire();
m_corpses.erase(p->GetGUIDLow());
_corpseslock.Release();
}
Corpse * ObjectMgr::GetCorpse(uint32 corpseguid)
{
Corpse * rv;
_corpseslock.Acquire();
CorpseMap::const_iterator itr = m_corpses.find(corpseguid);
rv = (itr != m_corpses.end()) ? itr->second : 0;
_corpseslock.Release();
return rv;
}
Transporter * ObjectMgr::GetTransporter(uint64 guid)
{
Transporter * rv;
_TransportLock.Acquire();
HM_NAMESPACE::hash_map::const_iterator itr = mTransports.find(guid);
rv = (itr != mTransports.end()) ? itr->second : 0;
_TransportLock.Release();
return rv;
}
void ObjectMgr::AddTransport(Transporter *pTransporter)
{
_TransportLock.Acquire();
mTransports[pTransporter->GetGUID()]=pTransporter;
_TransportLock.Release();
}
Transporter * ObjectMgr::GetTransporterByEntry(uint32 entry)
{
Transporter * rv = 0;
_TransportLock.Acquire();
HM_NAMESPACE::hash_map::iterator itr = mTransports.begin();
for(; itr != mTransports.end(); ++itr)
{
if(itr->second->GetEntry() == entry)
{
rv = itr->second;
break;
}
}
_TransportLock.Release();
return rv;
}
void ObjectMgr::LoadGuildCharters()
{
m_hiCharterId = 0;
QueryResult * result = CharacterDatabase.Query("SELECT * FROM charters");
if(!result) return;
do
{
Charter * c = new Charter(result->Fetch());
m_charters[c->GetID()] = c;
if(c->GetID() > m_hiCharterId)
m_hiCharterId = c->GetID();
} while(result->NextRow());
delete result;
Log.Notice("ObjectMgr", "%u charters loaded.", m_charters.size());
}
Charter * ObjectMgr::GetCharter(uint32 CharterId)
{
Charter * rv;
HM_NAMESPACE::hash_map::iterator itr;
m_charterLock.AcquireReadLock();
itr = m_charters.find(CharterId);
rv = (itr == m_charters.end()) ? 0 : itr->second;
m_charterLock.ReleaseReadLock();
return rv;
}
Charter * ObjectMgr::CreateCharter(uint32 LeaderGuid)
{
m_charterLock.AcquireWriteLock();
Charter * c = new Charter(++m_hiCharterId, LeaderGuid);
m_charters[c->GetID()] = c;
m_charterLock.ReleaseWriteLock();
return c;
}
Charter::Charter(Field * fields)
{
uint32 f = 0;
CharterId = fields[f++].GetUInt32();
LeaderGuid = fields[f++].GetUInt32();
GuildName = fields[f++].GetString();
ItemGuid = fields[f++].GetUInt64();
SignatureCount = 0;
for(uint32 i = 0; i < 9; ++i)
{
Signatures[i] = fields[f++].GetUInt32();
if(Signatures[i])
++SignatureCount;
}
}
void Charter::AddSignature(uint32 PlayerGuid)
{
if(SignatureCount >= 9)
return;
SignatureCount++;
uint32 i;
for(i = 0; i < 9; ++i)
{
if(Signatures[i] == 0)
{
Signatures[i] = PlayerGuid;
break;
}
}
assert(i != 9);
}
void Charter::RemoveSignature(uint32 PlayerGuid)
{
for(uint32 i = 0; i < 9; ++i)
{
if(Signatures[i] == PlayerGuid)
{
Signatures[i] = 0;
SignatureCount--;
SaveToDB();
break;
}
}
}
void Charter::Destroy()
{
//meh remove from objmgr
objmgr.RemoveCharter(this);
// Kill the players with this (in db/offline)
CharacterDatabase.Execute("UPDATE characters SET charterId = 0 WHERE charterId = %u", CharterId);
CharacterDatabase.Execute("DELETE FROM charters WHERE charterId = %u", CharterId);
Player * p;
for(uint32 i = 0; i < 9; ++i)
{
if(!Signatures[i])
continue;
p = objmgr.GetPlayer(Signatures[i]) ;
if(p)
p->m_charter = 0;
}
// click, click, boom!
delete this;
}
void Charter::SaveToDB()
{
CharacterDatabase.Execute(
"REPLACE INTO charters VALUES(%u,%u,'%s',"I64FMTD",%u,%u,%u,%u,%u,%u,%u,%u,%u)",
CharterId,LeaderGuid,GuildName.c_str(),ItemGuid,Signatures[0],Signatures[1],
Signatures[2],Signatures[3],Signatures[4],Signatures[5],
Signatures[6],Signatures[7],Signatures[8]);
}
Charter * ObjectMgr::GetCharterByItemGuid(uint64 guid)
{
Charter * rv = 0;
m_charterLock.AcquireReadLock();
HM_NAMESPACE::hash_map::iterator itr = m_charters.begin();
for(; itr != m_charters.end(); ++itr)
{
if(itr->second->ItemGuid == guid)
{
rv = itr->second;
break;
}
}
m_charterLock.ReleaseReadLock();
return rv;
}
Charter * ObjectMgr::GetCharterByName(string &charter_name)
{
Charter * rv = 0;
m_charterLock.AcquireReadLock();
HM_NAMESPACE::hash_map::iterator itr = m_charters.begin();
for(; itr != m_charters.end(); ++itr)
{
if(itr->second->GuildName == charter_name)
{
rv = itr->second;
break;
}
}
m_charterLock.ReleaseReadLock();
return rv;
}
void ObjectMgr::RemoveCharter(Charter * c)
{
m_charterLock.AcquireWriteLock();
m_charters.erase(c->CharterId);
m_charterLock.ReleaseWriteLock();
}
void ObjectMgr::LoadReputationModifierTable(const char * tablename, ReputationModMap * dmap)
{
QueryResult * result = WorldDatabase.Query("SELECT * FROM %s", tablename);
ReputationModMap::iterator itr;
ReputationModifier * modifier;
ReputationMod mod;
if(result)
{
do
{
mod.faction[0] = result->Fetch()[1].GetUInt32();
mod.faction[1] = result->Fetch()[2].GetUInt32();
mod.value = result->Fetch()[3].GetInt32();
mod.replimit = result->Fetch()[4].GetUInt32();
itr = dmap->find(result->Fetch()[0].GetUInt32());
if(itr == dmap->end())
{
modifier = new ReputationModifier;
modifier->entry = result->Fetch()[0].GetUInt32();
modifier->mods.push_back(mod);
dmap->insert( ReputationModMap::value_type( result->Fetch()[0].GetUInt32(), modifier ) );
}
else
{
itr->second->mods.push_back(mod);
}
} while(result->NextRow());
delete result;
}
Log.Notice("ObjectMgr", "%u reputation modifiers on %s.", dmap->size(), tablename);
}
void ObjectMgr::LoadReputationModifiers()
{
LoadReputationModifierTable("reputation_creature_onkill", &m_reputation_creature);
LoadReputationModifierTable("reputation_faction_onkill", &m_reputation_faction);
LoadInstanceReputationModifiers();
}
ReputationModifier * ObjectMgr::GetReputationModifier(uint32 entry_id, uint32 faction_id)
{
// first, try fetching from the creature table (by faction is a fallback)
ReputationModMap::iterator itr = m_reputation_creature.find(entry_id);
if(itr != m_reputation_creature.end())
return itr->second;
// fetch from the faction table
itr = m_reputation_faction.find(faction_id);
if(itr != m_reputation_faction.end())
return itr->second;
// no data. fallback to default -5 value.
return 0;
}
void ObjectMgr::LoadMonsterSay()
{
QueryResult * result = WorldDatabase.Query("SELECT * FROM npc_monstersay");
if(!result) return;
uint32 Entry, Event;
Field * fields = result->Fetch();
do
{
Entry = fields[0].GetUInt32();
Event = fields[1].GetUInt32();
if(Event >= NUM_MONSTER_SAY_EVENTS)
continue;
NpcMonsterSay * ms = new NpcMonsterSay;
ms->Chance = fields[2].GetFloat();
ms->Language = fields[3].GetUInt32();
ms->Type = fields[4].GetUInt32();
ms->MonsterName = fields[5].GetString() ? strdup(fields[5].GetString()) : "None";
char * texts[5];
char * text;
uint32 textcount = 0;
for(uint32 i = 0; i < 5; ++i)
{
text = (char*)fields[6+i].GetString();
if(!text) continue;
texts[textcount++] = strdup(fields[6+i].GetString());
// check for ;
if(texts[textcount-1][strlen(texts[textcount-1])-1] == ';')
texts[textcount-1][strlen(texts[textcount-1])-1] = 0;
}
if(!textcount)
{
delete ms;
continue;
}
ms->Texts = new const char*[textcount];
memcpy(ms->Texts, texts, sizeof(char*) * textcount);
ms->TextCount = textcount;
mMonsterSays[Event].insert( make_pair( Entry, ms ) );
} while(result->NextRow());
Log.Notice("ObjectMgr", "%u monster say events loaded.", result->GetRowCount());
delete result;
}
void ObjectMgr::HandleMonsterSayEvent(Creature * pCreature, MONSTER_SAY_EVENTS Event)
{
MonsterSayMap::iterator itr = mMonsterSays[Event].find(pCreature->GetEntry());
if(itr == mMonsterSays[Event].end())
return;
NpcMonsterSay * ms = itr->second;
if(Rand(ms->Chance))
{
// chance successful.
int choice = (ms->TextCount == 1) ? 0 : sRand.randInt(ms->TextCount - 1);
const char * text = ms->Texts[choice];
pCreature->SendChatMessage(ms->Type, ms->Language, text);
}
}
bool ObjectMgr::HasMonsterSay(uint32 Entry, MONSTER_SAY_EVENTS Event)
{
MonsterSayMap::iterator itr = mMonsterSays[Event].find(Entry);
if(itr == mMonsterSays[Event].end())
return false;
return true;
}
void ObjectMgr::LoadInstanceReputationModifiers()
{
QueryResult * result = WorldDatabase.Query("SELECT * FROM reputation_instance_onkill");
if(!result) return;
do
{
Field * fields = result->Fetch();
InstanceReputationMod mod;
mod.mapid = fields[0].GetUInt32();
mod.mob_rep_reward = fields[1].GetInt32();
mod.mob_rep_limit = fields[2].GetUInt32();
mod.boss_rep_reward = fields[3].GetInt32();
mod.boss_rep_limit = fields[4].GetUInt32();
mod.faction[0] = fields[5].GetUInt32();
mod.faction[1] = fields[6].GetUInt32();
HM_NAMESPACE::hash_map::iterator itr = m_reputation_instance.find(mod.mapid);
if(itr == m_reputation_instance.end())
{
InstanceReputationModifier * m = new InstanceReputationModifier;
m->mapid = mod.mapid;
m->mods.push_back(mod);
m_reputation_instance.insert( make_pair( m->mapid, m ) );
}
else
itr->second->mods.push_back(mod);
} while(result->NextRow());
delete result;
Log.Notice("ObjectMgr", "%u instance reputation modifiers loaded.", m_reputation_instance.size());
}
bool ObjectMgr::HandleInstanceReputationModifiers(Player * pPlayer, Unit * pVictim)
{
uint32 team = pPlayer->GetTeam();
bool is_boss;
if(pVictim->GetTypeId() != TYPEID_UNIT)
return false;
HM_NAMESPACE::hash_map::iterator itr = m_reputation_instance.find(pVictim->GetMapId());
if(itr == m_reputation_instance.end())
return false;
is_boss = /*((Creature*)pVictim)->GetCreatureName() ? ((Creature*)pVictim)->GetCreatureName()->Rank : */0;
if(!is_boss && ((Creature*)pVictim)->proto && ((Creature*)pVictim)->proto->boss)
is_boss = 1;
// Apply the bonuses as normal.
int32 replimit;
int32 value;
for(vector::iterator i = itr->second->mods.begin(); i != itr->second->mods.end(); ++i)
{
if(!(*i).faction[team])
continue;
if(is_boss)
{
value = i->boss_rep_reward;
replimit = i->boss_rep_limit;
}
else
{
value = i->mob_rep_reward;
replimit = i->mob_rep_reward;
}
if(!value || (replimit && pPlayer->GetStanding(i->faction[team]) >= replimit))
continue;
//value *= sWorld.getRate(RATE_KILLREPUTATION);
value = float2int32(float(value) * sWorld.getRate(RATE_KILLREPUTATION));
pPlayer->ModStanding(i->faction[team], value);
}
return true;
}
void ObjectMgr::LoadDisabledSpells()
{
QueryResult * result = WorldDatabase.Query("SELECT * FROM spell_disable");
if(result)
{
do
{
m_disabled_spells.insert( result->Fetch()[0].GetUInt32() );
} while(result->NextRow());
delete result;
}
result = WorldDatabase.Query("SELECT * FROM spell_disable_trainers");
if(result)
{
do
{
m_disabled_trainer_spells.insert( result->Fetch()[0].GetUInt32() );
} while(result->NextRow());
delete result;
}
Log.Notice("ObjectMgr", "%u disabled spells.", m_disabled_spells.size());
Log.Notice("ObjectMgr", "%u disabled trainer spells.", m_disabled_trainer_spells.size());
}
void ObjectMgr::LoadGroups()
{
QueryResult * result = CharacterDatabase.Query("SELECT * FROM groups");
if(result)
{
do
{
Group * g = new Group();
g->LoadFromDB(result->Fetch());
} while(result->NextRow());
delete result;
}
Log.Notice("ObjectMgr", "%u groups loaded.", this->mGroupSet.size());
}