Created
December 30, 2018 17:56
-
-
Save Shauren/8031b6b82283f0a409d760e8048cc861 to your computer and use it in GitHub Desktop.
npc_trainer converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace TrinityOld | |
{ | |
struct TrainerRequirement | |
{ | |
uint32 trainer_type; | |
uint32 trainer_spell; | |
uint32 trainer_class; | |
uint32 trainer_race; | |
}; | |
struct TrainerSpell | |
{ | |
int32 SpellId; | |
uint32 MoneyCost; | |
uint16 ReqSkillLine; | |
uint16 ReqSkillRank; | |
uint8 ReqLevel; | |
std::array<uint32, 3> ReqAbility; | |
friend bool operator<(TrainerSpell const& l, TrainerSpell const& r) { return l.SpellId < r.SpellId; } | |
friend bool operator==(TrainerSpell const& l, TrainerSpell const& r) { return l.SpellId == r.SpellId; } | |
}; | |
using trainer_spell_set_key = std::pair<TrainerRequirement*, std::set<TrainerSpell>*>; | |
struct compare_set_ptrs | |
{ | |
bool operator()(trainer_spell_set_key const& _Left, trainer_spell_set_key const& _Right) const | |
{ // apply operator< to operands | |
return std::tie(_Left.first->trainer_type, _Left.first->trainer_spell, _Left.first->trainer_class, _Left.first->trainer_race, *_Left.second) < | |
std::tie(_Right.first->trainer_type, _Right.first->trainer_spell, _Right.first->trainer_class, _Right.first->trainer_race, *_Right.second); | |
} | |
}; | |
std::unordered_map<uint32, TrainerRequirement> trainerRequirements; | |
std::unordered_map<uint32, std::set<TrainerSpell>> trainerSpellsByTrainerIdInitial; | |
std::unordered_map<uint32, std::set<TrainerSpell>> trainerSpellsByTrainerIdExpanded; | |
std::map<trainer_spell_set_key, std::set<uint32>, compare_set_ptrs> trainersBySpellSet; | |
void load_old_requirements() | |
{ | |
QueryResult creatureTemplate = WorldDatabase.Query("SELECT entry,trainer_type,trainer_spell,trainer_class,trainer_race FROM creature_template WHERE trainer_type!=0 OR trainer_spell!=0 OR trainer_class!=0 OR trainer_race!=0"); | |
if (!creatureTemplate) | |
return; | |
do | |
{ | |
Field* fields = creatureTemplate->Fetch(); | |
TrainerRequirement& req = trainerRequirements[fields[0].GetUInt32()]; | |
req.trainer_type = fields[1].GetUInt32(); | |
req.trainer_spell = fields[2].GetUInt32(); | |
req.trainer_class = fields[3].GetUInt32(); | |
req.trainer_race = fields[4].GetUInt32(); | |
} while (creatureTemplate->NextRow()); | |
} | |
void load_old_trainers() | |
{ | |
QueryResult npcTrainer = WorldDatabase.Query("SELECT ID,SpellID,MoneyCost,ReqSkillLine,ReqSkillRank,ReqLevel FROM npc_trainer"); | |
if (!npcTrainer) | |
return; | |
do | |
{ | |
Field* fields = npcTrainer->Fetch(); | |
uint32 id = fields[0].GetUInt32(); | |
TrainerSpell trainerSpell; | |
trainerSpell.SpellId = fields[1].GetInt32(); | |
trainerSpell.MoneyCost = fields[2].GetUInt32(); | |
trainerSpell.ReqSkillLine = fields[3].GetUInt16(); | |
trainerSpell.ReqSkillRank = fields[4].GetUInt16(); | |
trainerSpell.ReqLevel = fields[5].GetUInt8(); | |
trainerSpell.ReqAbility.fill(0); | |
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(trainerSpell.SpellId)) | |
{ | |
std::vector<uint32> reqAbilities; | |
if (spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) | |
{ | |
for (std::size_t i = 0; i < MAX_SPELL_EFFECTS; ++i) | |
{ | |
if (spellInfo->Effects[i].IsEffect(SPELL_EFFECT_LEARN_SPELL)) | |
{ | |
if (uint32 prevRank = sSpellMgr->GetPrevSpellInChain(spellInfo->Effects[i].TriggerSpell)) | |
reqAbilities.push_back(prevRank); | |
for (auto reqs : sSpellMgr->GetSpellsRequiredForSpellBounds(spellInfo->Effects[i].TriggerSpell)) | |
reqAbilities.push_back(reqs.second); | |
} | |
} | |
} | |
else | |
{ | |
if (uint32 prevRank = sSpellMgr->GetPrevSpellInChain(spellInfo->Id)) | |
reqAbilities.push_back(prevRank); | |
for (auto reqs : sSpellMgr->GetSpellsRequiredForSpellBounds(spellInfo->Id)) | |
reqAbilities.push_back(reqs.second); | |
} | |
for (std::size_t i = 0; i < std::min(reqAbilities.size(), size_t(3)); ++i) | |
trainerSpell.ReqAbility[i] = reqAbilities[i]; | |
} | |
trainerSpellsByTrainerIdInitial[id].insert(trainerSpell); | |
} while (npcTrainer->NextRow()); | |
} | |
void expand_trainer_reference(uint32 trainerId, std::set<TrainerSpell> const& oldSpells) | |
{ | |
for (auto spellItr = oldSpells.begin(); spellItr != oldSpells.end(); ++spellItr) | |
{ | |
if (spellItr->SpellId < 0) | |
expand_trainer_reference(trainerId, trainerSpellsByTrainerIdInitial[-spellItr->SpellId]); | |
else if (trainerId < 200000) | |
trainerSpellsByTrainerIdExpanded[trainerId].insert(*spellItr); | |
} | |
} | |
void expand_trainer_references() | |
{ | |
for (auto&& p : trainerSpellsByTrainerIdInitial) | |
expand_trainer_reference(p.first, p.second); | |
} | |
void collect_trainer_spell_sets() | |
{ | |
TrainerRequirement* const empty = new TrainerRequirement(); | |
empty->trainer_type = 2; | |
empty->trainer_class = 0; | |
empty->trainer_race = 0; | |
empty->trainer_spell = 0; | |
for (auto itr = trainerSpellsByTrainerIdExpanded.begin(); itr != trainerSpellsByTrainerIdExpanded.end(); ++itr) | |
{ | |
TrainerRequirement* requirement = Trinity::Containers::MapGetValuePtr(trainerRequirements, itr->first); | |
if (!requirement) | |
requirement = empty; | |
trainersBySpellSet[std::make_pair(requirement, &itr->second)].insert(itr->first); | |
} | |
} | |
void output_sql() | |
{ | |
uint32 trainerIdGenerator = 1; | |
TC_LOG_ERROR("sql.sql", "INSERT INTO `trainer` (`Id`,`Type`,`Requirement`,`Greeting`,`VerifiedBuild`) VALUES"); | |
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr) | |
{ | |
uint32 requirement = 0; | |
switch (itr->first.first->trainer_type) | |
{ | |
case 0: | |
requirement = itr->first.first->trainer_class; | |
break; | |
case 1: | |
requirement = itr->first.first->trainer_race; | |
break; | |
case 2: | |
requirement = itr->first.first->trainer_spell; | |
break; | |
case 3: | |
default: | |
break; | |
} | |
TC_LOG_ERROR("sql.sql", "(%u,%u,%u,NULL,0),", trainerIdGenerator, itr->first.first->trainer_type, requirement); | |
++trainerIdGenerator; | |
} | |
trainerIdGenerator = 1; | |
TC_LOG_ERROR("sql.sql", "INSERT INTO `trainer_spell` (`TrainerId`,`SpellId`,`MoneyCost`,`ReqSkillLine`,`ReqSkillRank`,`ReqAbility1`,`ReqAbility2`,`ReqAbility3`,`ReqLevel`,`VerifiedBuild`) VALUES"); | |
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr) | |
{ | |
for (TrainerSpell const& tSpell : *itr->first.second) | |
{ | |
TC_LOG_ERROR("sql.sql", "(%u,%u,%u,%u,%u,%u,%u,%u,%u,0),", | |
trainerIdGenerator, tSpell.SpellId, tSpell.MoneyCost, tSpell.ReqSkillLine, tSpell.ReqSkillRank, | |
tSpell.ReqAbility[0], tSpell.ReqAbility[1], tSpell.ReqAbility[2], tSpell.ReqLevel); | |
} | |
++trainerIdGenerator; | |
} | |
trainerIdGenerator = 1; | |
TC_LOG_ERROR("sql.sql", "INSERT INTO `creature_default_trainer` (`CreatureId`,`TrainerId`) VALUES"); | |
for (auto itr = trainersBySpellSet.begin(); itr != trainersBySpellSet.end(); ++itr) | |
{ | |
for (uint32 creatureId : itr->second) | |
{ | |
TC_LOG_ERROR("sql.sql", "(%u,%u),", creatureId, trainerIdGenerator); | |
} | |
++trainerIdGenerator; | |
} | |
} | |
void convert_old_trainers() | |
{ | |
load_old_requirements(); | |
load_old_trainers(); | |
expand_trainer_references(); | |
collect_trainer_spell_sets(); | |
output_sql(); | |
exit(0); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment