[10867] Implement templates for trainer spell data in npc_trainer_template.

New table let avoid duplication similar trainer spells for different trainers.
This commit is contained in:
VladimirMangos 2010-12-13 15:10:16 +03:00
parent f228a1c08d
commit 1d8f222621
15 changed files with 229 additions and 77 deletions

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0', `cache_id` int(10) default '0',
`required_10864_01_mangos_spell_proc_event` bit(1) default NULL `required_10867_02_mangos_creature_template` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -1252,6 +1252,7 @@ CREATE TABLE `creature_template` (
`movementId` int(11) UNSIGNED DEFAULT '0' NOT NULL, `movementId` int(11) UNSIGNED DEFAULT '0' NOT NULL,
`RegenHealth` tinyint(3) unsigned NOT NULL default '1', `RegenHealth` tinyint(3) unsigned NOT NULL default '1',
`equipment_id` mediumint(8) unsigned NOT NULL default '0', `equipment_id` mediumint(8) unsigned NOT NULL default '0',
`trainer_id` mediumint(8) unsigned NOT NULL default '0',
`vendor_id` mediumint(8) unsigned NOT NULL default '0', `vendor_id` mediumint(8) unsigned NOT NULL default '0',
`mechanic_immune_mask` int(10) unsigned NOT NULL default '0', `mechanic_immune_mask` int(10) unsigned NOT NULL default '0',
`flags_extra` int(10) unsigned NOT NULL default '0', `flags_extra` int(10) unsigned NOT NULL default '0',
@ -3990,6 +3991,30 @@ LOCK TABLES `npc_trainer` WRITE;
/*!40000 ALTER TABLE `npc_trainer` ENABLE KEYS */; /*!40000 ALTER TABLE `npc_trainer` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
--
-- Table structure for table `npc_trainer_template`
--
DROP TABLE IF EXISTS `npc_trainer_template`;
CREATE TABLE `npc_trainer_template` (
`entry` mediumint(8) unsigned NOT NULL default '0',
`spell` mediumint(8) unsigned NOT NULL default '0',
`spellcost` int(10) unsigned NOT NULL default '0',
`reqskill` smallint(5) unsigned NOT NULL default '0',
`reqskillvalue` smallint(5) unsigned NOT NULL default '0',
`reqlevel` tinyint(3) unsigned NOT NULL default '0',
UNIQUE KEY `entry_spell` (`entry`,`spell`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `npc_trainer_template`
--
LOCK TABLES `npc_trainer` WRITE;
/*!40000 ALTER TABLE `npc_trainer_template` DISABLE KEYS */;
/*!40000 ALTER TABLE `npc_trainer_template` ENABLE KEYS */;
UNLOCK TABLES;
-- --
-- Table structure for table `npc_vendor` -- Table structure for table `npc_vendor`
-- --

View file

@ -0,0 +1,12 @@
ALTER TABLE db_version CHANGE COLUMN required_10864_01_mangos_spell_proc_event required_10867_01_mangos_npc_trainer_template bit;
DROP TABLE IF EXISTS `npc_trainer_template`;
CREATE TABLE `npc_trainer_template` (
`entry` mediumint(8) unsigned NOT NULL default '0',
`spell` mediumint(8) unsigned NOT NULL default '0',
`spellcost` int(10) unsigned NOT NULL default '0',
`reqskill` smallint(5) unsigned NOT NULL default '0',
`reqskillvalue` smallint(5) unsigned NOT NULL default '0',
`reqlevel` tinyint(3) unsigned NOT NULL default '0',
UNIQUE KEY `entry_spell` (`entry`,`spell`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_10867_01_mangos_npc_trainer_template required_10867_02_mangos_creature_template bit;
ALTER TABLE creature_template
ADD COLUMN trainer_id mediumint(8) unsigned NOT NULL default '0' AFTER equipment_id;

View file

@ -133,6 +133,8 @@ pkgdata_DATA = \
10862_01_characters_mail.sql \ 10862_01_characters_mail.sql \
10863_01_mangos_spell_proc_event.sql \ 10863_01_mangos_spell_proc_event.sql \
10864_01_mangos_spell_proc_event.sql \ 10864_01_mangos_spell_proc_event.sql \
10867_01_mangos_npc_trainer_template.sql \
10867_02_mangos_creature_template.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -246,4 +248,6 @@ EXTRA_DIST = \
10862_01_characters_mail.sql \ 10862_01_characters_mail.sql \
10863_01_mangos_spell_proc_event.sql \ 10863_01_mangos_spell_proc_event.sql \
10864_01_mangos_spell_proc_event.sql \ 10864_01_mangos_spell_proc_event.sql \
10867_01_mangos_npc_trainer_template.sql \
10867_02_mangos_creature_template.sql \
README README

View file

@ -730,10 +730,11 @@ bool Creature::IsTrainerOf(Player* pPlayer, bool msg) const
// pet trainers not have spells in fact now // pet trainers not have spells in fact now
if (GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS) if (GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS)
{ {
TrainerSpellData const* trainer_spells = GetTrainerSpells(); TrainerSpellData const* cSpells = GetTrainerSpells();
TrainerSpellData const* tSpells = GetTrainerTemplateSpells();
// for not pet trainer expected not empty trainer list always // for not pet trainer expected not empty trainer list always
if (!trainer_spells || trainer_spells->spellList.empty()) if ((!cSpells || cSpells->spellList.empty()) && (!tSpells || tSpells->spellList.empty()))
{ {
sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.", sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.",
GetGUIDLow(),GetEntry()); GetGUIDLow(),GetEntry());
@ -2181,7 +2182,8 @@ VendorItemData const* Creature::GetVendorItems() const
VendorItemData const* Creature::GetVendorTemplateItems() const VendorItemData const* Creature::GetVendorTemplateItems() const
{ {
return GetCreatureInfo()->vendorId ? sObjectMgr.GetNpcVendorItemList(GetCreatureInfo()->vendorId) : NULL; uint32 vendorId = GetCreatureInfo()->vendorId;
return vendorId ? sObjectMgr.GetNpcVendorItemList(vendorId) : NULL;
} }
uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem) uint32 Creature::GetVendorItemCurrentCount(VendorItem const* vItem)
@ -2256,6 +2258,12 @@ uint32 Creature::UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 us
return vCount->count; return vCount->count;
} }
TrainerSpellData const* Creature::GetTrainerTemplateSpells() const
{
uint32 trainerId = GetCreatureInfo()->trainerId;
return trainerId ? sObjectMgr.GetNpcTrainerTemplateSpells(trainerId) : NULL;
}
TrainerSpellData const* Creature::GetTrainerSpells() const TrainerSpellData const* Creature::GetTrainerSpells() const
{ {
return sObjectMgr.GetNpcTrainerSpells(GetEntry()); return sObjectMgr.GetNpcTrainerSpells(GetEntry());

View file

@ -130,6 +130,7 @@ struct CreatureInfo
uint32 movementId; uint32 movementId;
bool RegenHealth; bool RegenHealth;
uint32 equipmentId; uint32 equipmentId;
uint32 trainerId;
uint32 vendorId; uint32 vendorId;
uint32 MechanicImmuneMask; uint32 MechanicImmuneMask;
uint32 flags_extra; uint32 flags_extra;
@ -515,6 +516,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
uint32 GetVendorItemCurrentCount(VendorItem const* vItem); uint32 GetVendorItemCurrentCount(VendorItem const* vItem);
uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count); uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count);
TrainerSpellData const* GetTrainerTemplateSpells() const;
TrainerSpellData const* GetTrainerSpells() const; TrainerSpellData const* GetTrainerSpells() const;
CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; } CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; }

View file

@ -467,8 +467,12 @@ bool ChatHandler::HandleReloadNpcGossipCommand(char* /*args*/)
bool ChatHandler::HandleReloadNpcTrainerCommand(char* /*args*/) bool ChatHandler::HandleReloadNpcTrainerCommand(char* /*args*/)
{ {
sLog.outString( "Re-Loading `npc_trainer_template` Table!" );
sObjectMgr.LoadTrainerTemplates();
SendGlobalSysMessage("DB table `npc_trainer_template` reloaded.");
sLog.outString( "Re-Loading `npc_trainer` Table!" ); sLog.outString( "Re-Loading `npc_trainer` Table!" );
sObjectMgr.LoadTrainerSpell(); sObjectMgr.LoadTrainers();
SendGlobalSysMessage("DB table `npc_trainer` reloaded."); SendGlobalSysMessage("DB table `npc_trainer` reloaded.");
return true; return true;
} }

View file

@ -111,6 +111,27 @@ void WorldSession::SendTrainerList(ObjectGuid guid)
SendTrainerList(guid, str); SendTrainerList(guid, str);
} }
static void SendTrainerSpellHelper(WorldPacket& data, TrainerSpell const* tSpell, TrainerSpellState state, float fDiscountMod, bool can_learn_primary_prof)
{
bool primary_prof_first_rank = sSpellMgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
SpellChainNode const* chain_node = sSpellMgr.GetSpellChainNode(tSpell->learnedSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
data << uint32(floor(tSpell->spellCost * fDiscountMod));
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0);
// primary prof. learn confirmation dialog
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state
data << uint8(tSpell->reqLevel);
data << uint32(tSpell->reqSkill);
data << uint32(tSpell->reqSkillValue);
data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
data << uint32(0);
}
void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
{ {
DEBUG_LOG( "WORLD: SendTrainerList" ); DEBUG_LOG( "WORLD: SendTrainerList" );
@ -134,57 +155,68 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle)
if (!ci) if (!ci)
return; return;
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); TrainerSpellData const* cSpells = unit->GetTrainerSpells();
if (!trainer_spells) TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
{ {
DEBUG_LOG("WORLD: SendTrainerList - Training spells not found for %s", guid.GetString().c_str()); DEBUG_LOG("WORLD: SendTrainerList - Training spells not found for %s", guid.GetString().c_str());
return; return;
} }
WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); uint32 maxcount = (cSpells ? cSpells->spellList.size() : 0) + (tSpells ? tSpells->spellList.size() : 0);
WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+maxcount*38 + strTitle.size()+1);
data << ObjectGuid(guid); data << ObjectGuid(guid);
data << uint32(trainer_spells->trainerType); data << uint32(cSpells->trainerType ? cSpells->trainerType : tSpells->trainerType);
size_t count_pos = data.wpos(); size_t count_pos = data.wpos();
data << uint32(trainer_spells->spellList.size()); data << uint32(maxcount);
// reputation discount // reputation discount
float fDiscountMod = _player->GetReputationPriceDiscount(unit); float fDiscountMod = _player->GetReputationPriceDiscount(unit);
bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0; bool can_learn_primary_prof = GetPlayer()->GetFreePrimaryProfessionPoints() > 0;
uint32 count = 0; uint32 count = 0;
for(TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
if (cSpells)
{ {
TrainerSpell const* tSpell = &itr->second; for(TrainerSpellMap::const_iterator itr = cSpells->spellList.begin(); itr != cSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell)) if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
continue; continue;
bool primary_prof_first_rank = sSpellMgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell); TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
SpellChainNode const* chain_node = sSpellMgr.GetSpellChainNode(tSpell->learnedSpell);
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof);
data << uint8(state==TRAINER_SPELL_GREEN_DISABLED ? TRAINER_SPELL_GREEN : state);
data << uint32(floor(tSpell->spellCost * fDiscountMod));
data << uint32(primary_prof_first_rank && can_learn_primary_prof ? 1 : 0); ++count;
// primary prof. learn confirmation dialog }
data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state }
data << uint8(tSpell->reqLevel);
data << uint32(tSpell->reqSkill);
data << uint32(tSpell->reqSkillValue);
data << uint32(!tSpell->IsCastable() && chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0);
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->req : 0);
data << uint32(0);
++count; if (tSpells)
{
for(TrainerSpellMap::const_iterator itr = tSpells->spellList.begin(); itr != tSpells->spellList.end(); ++itr)
{
TrainerSpell const* tSpell = &itr->second;
if(!_player->IsSpellFitByClassAndRace(tSpell->learnedSpell))
continue;
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
SendTrainerSpellHelper(data, tSpell, state, fDiscountMod, can_learn_primary_prof);
++count;
}
} }
data << strTitle; data << strTitle;
data.put<uint32>(count_pos,count); data.put<uint32>(count_pos,count);
SendPacket( &data ); SendPacket(&data);
} }
void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data ) void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
@ -210,12 +242,17 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
return; return;
// check present spell in trainer spell list // check present spell in trainer spell list
TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); TrainerSpellData const* cSpells = unit->GetTrainerSpells();
if (!trainer_spells) TrainerSpellData const* tSpells = unit->GetTrainerTemplateSpells();
if (!cSpells && !tSpells)
return; return;
// not found, cheat? // not found, cheat?
TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); TrainerSpell const* trainer_spell = cSpells->Find(spellId);
if (!trainer_spell)
trainer_spell = tSpells->Find(spellId);
if (!trainer_spell) if (!trainer_spell)
return; return;

View file

@ -8825,29 +8825,31 @@ void ObjectMgr::LoadMailLevelRewards()
sLog.outString( ">> Loaded %u level dependent mail rewards,", count ); sLog.outString( ">> Loaded %u level dependent mail rewards,", count );
} }
void ObjectMgr::LoadTrainerSpell() void ObjectMgr::LoadTrainers(char const* tableName, bool isTemplates)
{ {
CacheTrainerSpellMap& trainerList = isTemplates ? m_mCacheTrainerTemplateSpellMap : m_mCacheTrainerSpellMap;
// For reload case // For reload case
for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) for (CacheTrainerSpellMap::iterator itr = trainerList.begin(); itr != trainerList.end(); ++itr)
itr->second.Clear(); itr->second.Clear();
m_mCacheTrainerSpellMap.clear(); trainerList.clear();
std::set<uint32> skip_trainers; std::set<uint32> skip_trainers;
QueryResult *result = WorldDatabase.Query("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer"); QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM %s", tableName);
if( !result ) if (!result)
{ {
barGoLink bar( 1 ); barGoLink bar(1);
bar.step(); bar.step();
sLog.outString(); sLog.outString();
sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!"); sLog.outErrorDb(">> Loaded `%s`, table is empty!", tableName);
return; return;
} }
barGoLink bar( (int)result->GetRowCount() ); barGoLink bar((int)result->GetRowCount());
std::set<uint32> talentIds; std::set<uint32> talentIds;
@ -8861,48 +8863,60 @@ void ObjectMgr::LoadTrainerSpell()
uint32 entry = fields[0].GetUInt32(); uint32 entry = fields[0].GetUInt32();
uint32 spell = fields[1].GetUInt32(); uint32 spell = fields[1].GetUInt32();
CreatureInfo const* cInfo = GetCreatureTemplate(entry);
if(!cInfo)
{
sLog.outErrorDb("Table `npc_trainer` have entry for nonexistent creature template (Entry: %u), ignore", entry);
continue;
}
if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
{
if (skip_trainers.find(entry) == skip_trainers.end())
{
sLog.outErrorDb("Table `npc_trainer` have data for creature (Entry: %u) without trainer flag, ignore", entry);
skip_trainers.insert(entry);
}
continue;
}
SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell);
if(!spellinfo) if (!spellinfo)
{ {
sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell); sLog.outErrorDb("Table `%s` for trainer (Entry: %u ) has non existing spell %u, ignore", tableName, entry, spell);
continue; continue;
} }
if(!SpellMgr::IsSpellValid(spellinfo)) if (!SpellMgr::IsSpellValid(spellinfo))
{ {
sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell); sLog.outErrorDb("Table `%s` for trainer (Entry: %u) has broken learning spell %u, ignore", tableName, entry, spell);
continue; continue;
} }
if(GetTalentSpellCost(spell)) if (GetTalentSpellCost(spell))
{ {
if (talentIds.find(spell) == talentIds.end()) if (talentIds.find(spell) == talentIds.end())
{ {
sLog.outErrorDb("Table `npc_trainer` has talent as learning spell %u, ignore", spell); sLog.outErrorDb("Table `%s` has talent as learning spell %u, ignore", tableName, spell);
talentIds.insert(spell); talentIds.insert(spell);
} }
continue; continue;
} }
TrainerSpellData& data = m_mCacheTrainerSpellMap[entry]; if (!isTemplates)
{
CreatureInfo const* cInfo = GetCreatureTemplate(entry);
if (!cInfo)
{
sLog.outErrorDb("Table `%s` have entry for nonexistent creature template (Entry: %u), ignore", tableName, entry);
continue;
}
if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
{
if (skip_trainers.find(entry) == skip_trainers.end())
{
sLog.outErrorDb("Table `%s` have data for creature (Entry: %u) without trainer flag, ignore", tableName, entry);
skip_trainers.insert(entry);
}
continue;
}
if (TrainerSpellData const* tSpells = cInfo->trainerId ? GetNpcTrainerTemplateSpells(cInfo->trainerId) : NULL)
{
if (tSpells->spellList.find(spell) != tSpells->spellList.end())
{
sLog.outErrorDb("Table `%s` for trainer (Entry: %u) has spell %u listed in trainer template %u, ignore", tableName, entry, spell);
continue;
}
}
}
TrainerSpellData& data = trainerList[entry];
TrainerSpell& trainerSpell = data.spellList[spell]; TrainerSpell& trainerSpell = data.spellList[spell];
trainerSpell.spell = spell; trainerSpell.spell = spell;
@ -8927,7 +8941,7 @@ void ObjectMgr::LoadTrainerSpell()
} }
} }
if(SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell)) if (SpellMgr::IsProfessionSpell(trainerSpell.learnedSpell))
data.trainerType = 2; data.trainerType = 2;
++count; ++count;
@ -8936,7 +8950,35 @@ void ObjectMgr::LoadTrainerSpell()
delete result; delete result;
sLog.outString(); sLog.outString();
sLog.outString( ">> Loaded %d Trainers", count ); sLog.outString( ">> Loaded %d trainer %sspells", count, isTemplates ? "template " : "" );
}
void ObjectMgr::LoadTrainerTemplates()
{
LoadTrainers("npc_trainer_template", true);
// post loading check
std::set<uint32> trainer_ids;
for(CacheTrainerSpellMap::const_iterator tItr = m_mCacheTrainerTemplateSpellMap.begin(); tItr != m_mCacheTrainerTemplateSpellMap.end(); ++tItr)
trainer_ids.insert(tItr->first);
for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
{
if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
{
if (cInfo->trainerId)
{
if (trainer_ids.count(cInfo->trainerId) > 0)
trainer_ids.erase(cInfo->trainerId);
else
sLog.outErrorDb("Creature (Entry: %u) has trainer_id = %u for nonexistent trainer template", cInfo->Entry, cInfo->trainerId);
}
}
}
for(std::set<uint32>::const_iterator tItr = trainer_ids.begin(); tItr != trainer_ids.end(); ++tItr)
sLog.outErrorDb("Table `npc_trainer_template` has trainer template %u not used by any trainers ", *tItr);
} }
void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates) void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates)
@ -8988,7 +9030,7 @@ void ObjectMgr::LoadVendors(char const* tableName, bool isTemplates)
delete result; delete result;
sLog.outString(); sLog.outString();
sLog.outString( ">> Loaded %u vendor items", count); sLog.outString( ">> Loaded %u vendor %sitems", count, isTemplates ? "template " : "");
} }

View file

@ -972,7 +972,8 @@ class ObjectMgr
void LoadVendorTemplates(); void LoadVendorTemplates();
void LoadVendors() { LoadVendors("npc_vendor", false); } void LoadVendors() { LoadVendors("npc_vendor", false); }
void LoadTrainerSpell(); void LoadTrainerTemplates();
void LoadTrainers() { LoadTrainers("npc_trainer", false); }
std::string GeneratePetName(uint32 entry); std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint32 level) const; uint32 GetBaseXP(uint32 level) const;
@ -1202,13 +1203,22 @@ class ObjectMgr
TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const
{ {
CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry); CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry);
if(iter == m_mCacheTrainerSpellMap.end()) if(iter == m_mCacheTrainerSpellMap.end())
return NULL; return NULL;
return &iter->second; return &iter->second;
} }
TrainerSpellData const* GetNpcTrainerTemplateSpells(uint32 entry) const
{
CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerTemplateSpellMap.find(entry);
if(iter == m_mCacheTrainerTemplateSpellMap.end())
return NULL;
return &iter->second;
}
VendorItemData const* GetNpcVendorItemList(uint32 entry) const VendorItemData const* GetNpcVendorItemList(uint32 entry) const
{ {
CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry); CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry);
@ -1384,6 +1394,7 @@ class ObjectMgr
void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
void LoadQuestRelationsHelper(QuestRelationsMap& map, char const* table); void LoadQuestRelationsHelper(QuestRelationsMap& map, char const* table);
void LoadVendors(char const* tableName, bool isTemplates); void LoadVendors(char const* tableName, bool isTemplates);
void LoadTrainers(char const* tableName, bool isTemplates);
MailLevelRewardMap m_mailLevelRewardMap; MailLevelRewardMap m_mailLevelRewardMap;
@ -1433,6 +1444,7 @@ class ObjectMgr
CacheNpcTextIdMap m_mCacheNpcTextIdMap; CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorTemplateItemMap; CacheVendorItemMap m_mCacheVendorTemplateItemMap;
CacheVendorItemMap m_mCacheVendorItemMap; CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerTemplateSpellMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap; CacheTrainerSpellMap m_mCacheTrainerSpellMap;
}; };

View file

@ -21,8 +21,8 @@
#include "Database/SQLStorageImpl.h" #include "Database/SQLStorageImpl.h"
#include "Database/DatabaseEnv.h" #include "Database/DatabaseEnv.h"
const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiiis"; const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiiiis";
const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiiii"; const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiifffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiiiii";
const char CreatureDataAddonInfofmt[]="iiilliis"; const char CreatureDataAddonInfofmt[]="iiilliis";
const char CreatureModelfmt[]="iffbii"; const char CreatureModelfmt[]="iffbii";
const char CreatureInfoAddonInfofmt[]="iiilliis"; const char CreatureInfoAddonInfofmt[]="iiilliis";

View file

@ -1166,7 +1166,8 @@ void World::SetInitialWorldSettings()
sObjectMgr.LoadVendors(); // must be after load CreatureTemplate, VendorTemplate, and ItemTemplate sObjectMgr.LoadVendors(); // must be after load CreatureTemplate, VendorTemplate, and ItemTemplate
sLog.outString( "Loading Trainers..." ); sLog.outString( "Loading Trainers..." );
sObjectMgr.LoadTrainerSpell(); // must be after load CreatureTemplate sObjectMgr.LoadTrainerTemplates(); // must be after load CreatureTemplate
sObjectMgr.LoadTrainers(); // must be after load CreatureTemplate, TrainerTemplate
sLog.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement sLog.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement
sObjectMgr.LoadCreatureMovementScripts(); sObjectMgr.LoadCreatureMovementScripts();

View file

@ -253,6 +253,7 @@ class MANGOS_DLL_SPEC WorldSession
void SendTrainerList(ObjectGuid guid); void SendTrainerList(ObjectGuid guid);
void SendTrainerList(ObjectGuid guid, const std::string& strTitle ); void SendTrainerList(ObjectGuid guid, const std::string& strTitle );
void SendListInventory(ObjectGuid guid); void SendListInventory(ObjectGuid guid);
bool CheckBanker(ObjectGuid guid); bool CheckBanker(ObjectGuid guid);
void SendShowBank(ObjectGuid guid); void SendShowBank(ObjectGuid guid);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10866" #define REVISION_NR "10867"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_10862_01_characters_mail" #define REVISION_DB_CHARACTERS "required_10862_01_characters_mail"
#define REVISION_DB_MANGOS "required_10864_01_mangos_spell_proc_event" #define REVISION_DB_MANGOS "required_10867_02_mangos_creature_template"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__